Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scrub database dump: implement private fields for classes (1/3) #223

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions home/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,13 @@
from .intentionalwalk import IntentionalWalk
from .leaderboard import Leaderboard
from .weeklygoal import WeeklyGoal

ALL_MODELS = [
Account,
Contest,
DailyWalk,
Device,
IntentionalWalk,
Leaderboard,
WeeklyGoal,
]
17 changes: 16 additions & 1 deletion home/models/account.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from enum import Enum
from typing import List

from django.db import models
from setfield import SetField

from home.models.mixins.privacyprotectedfields import (
PrivacyProtectedFieldsMixin,
PrivateFieldInfo,
FieldType,
)

SAN_FRANCISCO_ZIP_CODES = set(
[
"94102",
Expand Down Expand Up @@ -72,7 +79,7 @@ class IsLatinoLabels(Enum):


# Note: Maybe inherit from Django's User model?
class Account(models.Model):
class Account(models.Model, PrivacyProtectedFieldsMixin):
"""
Stores a single user account as identified by email. This is created when
the app is installed and the user signs up for the first time and is has
Expand Down Expand Up @@ -150,5 +157,13 @@ class Account(models.Model):
def __str__(self):
return f"{self.name} | {self.email}"

@staticmethod
def privacy_protected_fields() -> List[PrivateFieldInfo]:
"""Privacy protected fields overrides the PrivacyProtectedFields mixin.c"""
return [
PrivateFieldInfo(name="email", type=FieldType.EMAIL),
PrivateFieldInfo(name="name", type=FieldType.NAME),
]

class Meta:
ordering = ("-created",)
Empty file added home/models/mixins/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions home/models/mixins/privacyprotectedfields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import List, TypedDict
from enum import Enum


class FieldType(Enum):
"""Represents data types for Faker to generate."""

EMAIL = "email"
NAME = "name"


class PrivateFieldInfo(TypedDict):
"""Represents a sensitive field in a model."""

name: str
type: FieldType


class PrivacyProtectedFieldsMixin:
"""Mixin to define sensitive fields in a model.

A downstream handler for a Model that extends this mixin should
implement the `privacy_protected_fields` method to return the list of
sensitive fields that should be scrubbed, hidden away or otherwise excluded.

Example use:
```python
class Account(models.Model, PrivacyProtectedFieldsMixin):
email = models.EmailField()
def privacy_protected_fields():
return ["email", "name"]
```
"""

@staticmethod
def privacy_protected_fields() -> List[PrivateFieldInfo]:
"""Return a list of sensitive fields in the model."""
raise NotImplementedError
11 changes: 11 additions & 0 deletions home/tests/unit/api/test_appuser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django.test import TestCase

from home.models.account import Account
from home.models.mixins.privacyprotectedfields import (
PrivacyProtectedFieldsMixin,
)
from home.views.api.appuser import is_tester, validate_account_input


Expand Down Expand Up @@ -64,3 +68,10 @@ def test_invalid_input(self):
for example in examples:
with self.assertRaises(AssertionError, msg=example):
validate_account_input(example)

def test_private(self):
# Just ensure the method is implemented,
# mainly for test coverage.
self.assertTrue(issubclass(Account, PrivacyProtectedFieldsMixin))
items = Account.privacy_protected_fields()
self.assertGreater(len(items), 0)