Skip to content

Commit

Permalink
Merge pull request #12 from xjlin0/add_note_as_past
Browse files Browse the repository at this point in the history
Add note as past in attendee detail page
  • Loading branch information
xjlin0 authored Jun 14, 2021
2 parents f561346 + 0d0c945 commit fb616ab
Show file tree
Hide file tree
Showing 15 changed files with 550 additions and 272 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,16 @@ https://dbdiagram.io/d/5d5ff66eced98361d6dddc48

## Todo:
- [x] make auth group not organization specific, and counselling note check on organization
- [ ] Past can replace Note, Attendee.progressions and calls/requests, so that any name lists such as status can be easily queried. (membership remains as attendance)
- [ ] attendee detail page
- [x] server side process of Attendees list & search page
- [x] AttendingMeet form of Attendee update page
- [x] FamilyAttendee datagrid of Attendee update page
- [x] Personal & family Address of Attendee update page
- [x] Dynamic contacts of Attendee update page
- [x] Permission controlled blocks in single attendee update page, i.e. different blocks/user-settings for different groups
- [x] Generic models such as Note, Place, Past need to have organization column instead of infos
- [x] Generic models such as Note, Place, Past need to have organization column instead of infos
- [x] Add Past as Note
- [ ] Create new instance of Attendee & attending update page with params with meet
- [x] Modify Attendee save method to combine/convert names by OpenCC to support searches in different text encoding, and retire db level full_name.
- [x] implement secret/private relation/past general
Expand Down
2 changes: 2 additions & 0 deletions attendees/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ def common_variables(request): # TODO move organization info to view
auth_groups__in=request.user.groups.all(),
category='main',
menuauthgroup__read=True,
organization=request.user.organization, # maybe None
is_removed=False,
).distinct()
if request.user.is_authenticated and request.user.organization:
user_organization = request.user.organization
Expand Down
34 changes: 26 additions & 8 deletions attendees/persons/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,33 @@ class PastAdmin(admin.ModelAdmin):
# Todo 20210528 combine with NoteAdmin's show_secret
search_fields = ('id', 'display_name', 'infos')
readonly_fields = ['id', 'created', 'modified']
list_display = ('subject', 'category', 'display_order', 'display_name', 'start')
list_display = ('subject', 'category', 'display_order', 'display_name', 'when')

def get_queryset(self, request):
qs = super().get_queryset(request)
counseling_category = Category.objects.get(type='note', display_name=Past.COUNSELING)

if request.resolver_match.func.__name__ == 'changelist_view':
messages.warning(request, 'Not all, but only those records accessible to you will be listed here.')
requester_permission = {'infos__show_secret__' + request.user.attendee_uuid_str(): True}
return qs.filter(
Q(organization=request.user.organization),
( Q(**requester_permission) | Q(infos__show_secret={}) | Q(infos__show_secret__isnull=True) ),
)

if request.user.is_counselor():
counselors_permission = {'infos__show_secret__' + Past.ALL_COUNSELORS: True}
return qs.filter(
Q(organization=request.user.organization),
(~Q(category=counseling_category)
|
(Q(category=counseling_category) and (Q(**requester_permission)
|
Q(**counselors_permission))
)),
)

else:
return qs.filter(
Q(organization=request.user.organization),
( Q(**requester_permission) | Q(infos__show_secret={}) | Q(infos__show_secret__isnull=True) ),
).exclude(category=counseling_category)


class FamilyAdmin(admin.ModelAdmin):
Expand Down Expand Up @@ -153,21 +169,23 @@ class NoteAdmin(SummernoteModelAdmin):

def get_queryset(self, request): # even super user cannot see all in DjangoAdmin
qs = super().get_queryset(request)
counseling_category = Category.objects.get(type='note', display_name=Note.COUNSELING)

if request.resolver_match.func.__name__ == 'changelist_view':
messages.warning(request, 'Not all, but only those notes accessible to you will be listed here.')
if request.user.is_counselor():
requester_permission = {'infos__show_secret__' + request.user.attendee_uuid_str(): True}
counselors_permission = {'infos__show_secret__' + Note.ALL_COUNSELORS: True}
return qs.filter(
Q(organization=request.user.organization),
(~Q(category=Note.COUNSELING)
(~Q(category=counseling_category)
|
(Q(category=Note.COUNSELING) and (Q(**requester_permission)
(Q(category=counseling_category) and (Q(**requester_permission)
|
Q(**counselors_permission))
)),
)
return qs.filter(organization=request.user.organization).exclude(category=Note.COUNSELING)
return qs.filter(organization=request.user.organization).exclude(category=counseling_category)


class RelationshipAdmin(admin.ModelAdmin):
Expand Down
8 changes: 4 additions & 4 deletions attendees/persons/migrations/0002_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ class Migration(migrations.Migration):
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('is_removed', models.BooleanField(default=False)),
('content_type', models.ForeignKey(on_delete=models.SET(0), to='contenttypes.ContentType')),
('display_order', models.SmallIntegerField(blank=False, default=0, null=False)),
('organization', models.ForeignKey(on_delete=models.SET(0), to='whereabouts.Organization')),
('category', models.ForeignKey(help_text="subtype: for note it's public/counseling sub-types etc", on_delete=models.SET(0), to='persons.Category')),
('display_order', models.SmallIntegerField(blank=False, default=0, null=False)),
('content_type', models.ForeignKey(on_delete=models.SET(0), to='contenttypes.ContentType')),
('object_id', models.CharField(max_length=36)),
('category', models.CharField(default='normal', help_text='normal, for-address, etc', max_length=20, blank=False, null=False, db_index=True)),
('body', models.TextField()),
('infos', JSONField(blank=True, default=Utility.relationship_infos, help_text='Example: {"owner": "John"}. Please keep {} here even no data', null=True)),
],
options={
'db_table': 'persons_notes',
'ordering': ('organization', 'content_type', 'display_order', '-modified',),
'ordering': ('organization', 'category', 'content_type', 'object_id', 'display_order', '-modified',),
},
),
migrations.AddIndex(
Expand Down
12 changes: 6 additions & 6 deletions attendees/persons/migrations/0003_past.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class Migration(migrations.Migration):
dependencies = [
('persons', '0002_note'),
]

operations = [
migrations.CreateModel(
name='Past',
Expand All @@ -26,19 +25,19 @@ class Migration(migrations.Migration):
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('is_removed', models.BooleanField(default=False)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
('object_id', models.CharField(max_length=36)),
('organization', models.ForeignKey(on_delete=models.SET(0), to='whereabouts.Organization')),
('category', models.ForeignKey(help_text="subtype: for education it's primary/high/college sub-types etc", on_delete=models.SET(0), to='persons.Category')),
('display_order', models.SmallIntegerField(db_index=True, default=30000)),
('organization', models.ForeignKey(on_delete=models.SET(0), to='whereabouts.Organization')),
('start', models.DateTimeField(blank=True, default=attendees.persons.models.utility.Utility.now_with_timezone, null=True)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
('object_id', models.CharField(max_length=36)),
('when', models.DateTimeField(blank=True, default=attendees.persons.models.utility.Utility.now_with_timezone, null=True)),
('finish', models.DateTimeField(blank=True, null=True)),
('display_name', models.CharField(blank=True, max_length=50, null=True)),
('infos', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=attendees.persons.models.utility.Utility.relationship_infos, help_text='Example: {"show_secret": {"attendee1id": true, "attendee2id": false}}. Please keep {} here even no data', null=True)),
],
options={
'db_table': 'persons_pasts',
'ordering': ('organization', 'category__type', 'display_order', 'category__display_order', 'start'),
'ordering': ('organization', 'category__type', 'display_order', 'category__display_order', 'when'),
},
bases=(models.Model, attendees.persons.models.utility.Utility),
),
Expand All @@ -47,3 +46,4 @@ class Migration(migrations.Migration):
index=django.contrib.postgres.indexes.GinIndex(fields=['infos'], name='past_infos_gin'),
),
]

4 changes: 2 additions & 2 deletions attendees/persons/migrations/0007_relationship_m2m.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class Migration(migrations.Migration):
('scheduler', models.BooleanField('to_attendee is the scheduler?', default=False, null=False, blank=False, help_text="[from_attendee decide:] to_attendee can view/change the schedules of the from_attendee?")),
('from_attendee', models.ForeignKey(on_delete=models.CASCADE, related_name='from_attendee', to='persons.Attendee')),
('to_attendee', models.ForeignKey(on_delete=models.CASCADE, related_name='to_attendee', to='persons.Attendee')),
('start', models.DateField(blank=True, null=True)),
('finish', models.DateTimeField(null=False, blank=False, default=Utility.forever, help_text='The relation will be ended at when')),
('start', models.DateTimeField(blank=True, null=True)),
('finish', models.DateTimeField(null=True, blank=True, help_text='The relation will be ended at when')),
('in_family', models.ForeignKey(blank=True, null=True, on_delete=models.SET_NULL, related_name='in_family', to='persons.Family')),
('infos', JSONField(blank=True, null=True, default=Utility.relationship_infos, help_text='Example: {"show_secret": {"attendee1id": true, "attendee2id": false}}. Please keep {} here even no data')),
],
Expand Down
4 changes: 2 additions & 2 deletions attendees/persons/models/note.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Note(UUIDModel, TimeStampedModel, SoftDeletableModel):
content_type = models.ForeignKey(ContentType, on_delete=models.SET(0))
object_id = models.CharField(max_length=36)
content_object = GenericForeignKey('content_type', 'object_id')
category = models.CharField(max_length=20, default='normal', blank=False, null=False, db_index=True, help_text="normal, for-address, etc")
category = models.ForeignKey('persons.Category', null=False, blank=False, on_delete=models.SET(0), help_text="subtype: for note it's public/counseling sub-types etc")
organization = models.ForeignKey('whereabouts.Organization', null=False, blank=False, on_delete=models.SET(0))
display_order = models.SmallIntegerField(default=0, blank=False, null=False)
body = models.TextField()
Expand All @@ -26,7 +26,7 @@ def __str__(self):

class Meta:
db_table = 'persons_notes'
ordering = ('organization', 'content_type', 'display_order', '-modified',)
ordering = ('organization', 'category', 'content_type', 'object_id', 'display_order', '-modified',)
indexes = [
GinIndex(fields=['infos'], name='note_infos_gin', ),
]
Expand Down
11 changes: 6 additions & 5 deletions attendees/persons/models/past.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
from django.contrib.postgres.fields.jsonb import JSONField
from django.contrib.postgres.indexes import GinIndex
from model_utils.models import TimeStampedModel, SoftDeletableModel, UUIDModel
from private_storage.fields import PrivateFileField
from . import Utility, Note
from . import Utility#, Note


class Past(UUIDModel, TimeStampedModel, SoftDeletableModel, Utility):
notes = GenericRelation(Note)
COUNSELING = 'counseling' # for private data, and only assigned counselors
ALL_COUNSELORS = 'all_counselors_' # for private data, but accessible to all counselors
#notes = GenericRelation(Note)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=False, blank=False)
object_id = models.CharField(max_length=36, null=False, blank=False)
subject = GenericForeignKey('content_type', 'object_id')
start = models.DateTimeField(null=True, blank=True, default=Utility.now_with_timezone)
when = models.DateTimeField(null=True, blank=True, default=Utility.now_with_timezone)
finish = models.DateTimeField(null=True, blank=True)
category = models.ForeignKey('persons.Category', null=False, blank=False, on_delete=models.SET(0), help_text="subtype: for education it's primary/high/college sub-types etc")
display_order = models.SmallIntegerField(default=30000, blank=False, null=False, db_index=True)
Expand All @@ -23,7 +24,7 @@ class Past(UUIDModel, TimeStampedModel, SoftDeletableModel, Utility):

class Meta:
db_table = 'persons_pasts'
ordering = ('organization', 'category__type', 'display_order', 'category__display_order', 'start')
ordering = ('organization', 'category__type', 'display_order', 'category__display_order', 'when')
indexes = [
GinIndex(fields=['infos'], name='past_infos_gin', ),
]
Expand Down
4 changes: 2 additions & 2 deletions attendees/persons/models/relationship.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Relationship(UUIDModel, TimeStampedModel, SoftDeletableModel, Utility):
emergency_contact = models.BooleanField('to_attendee is the emergency contact?', null=False, blank=False, default=False, help_text="[from_attendee decide:] Notify to_attendee of from_attendee's emergency?")
scheduler = models.BooleanField('to_attendee is the scheduler?', null=False, blank=False, default=False, help_text="[from_attendee decide:] to_attendee can view/change the schedules of the from_attendee?")
in_family = models.ForeignKey('persons.Family', null=True, blank=True, on_delete=models.SET_NULL, related_name="in_family")
start = models.DateField(null=True, blank=True)
finish = models.DateTimeField(blank=False, null=False, default=Utility.forever, help_text="The relation will be ended at when")
start = models.DateTimeField(null=True, blank=True)
finish = models.DateTimeField(blank=True, null=True, help_text="The relation will be ended at when")
infos = JSONField(null=True, blank=True, default=Utility.relationship_infos, help_text='Example: {"show_secret": {"attendee1id": true, "attendee2id": false}}. Please keep {} here even no data') # compare to NoteAdmin

class Meta:
Expand Down
2 changes: 1 addition & 1 deletion attendees/persons/models/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def attendee_infos():

@staticmethod
def relationship_infos():
return {"show_secret": {}, "comment": None}
return {"show_secret": {}, "comment": None, "body": None}

@staticmethod
def forever(): # 1923 years from now
Expand Down
2 changes: 1 addition & 1 deletion attendees/persons/serializers/past_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ class PastSerializer(serializers.ModelSerializer):

class Meta: # It is critical not to have organization in the fields, to let perform_create set it
model = Past
fields = ('id', 'display_name', 'category', 'start', 'finish', 'infos', 'content_type', 'object_id')
fields = ('id', 'display_name', 'category', 'when', 'finish', 'infos', 'content_type', 'object_id')

Loading

0 comments on commit fb616ab

Please sign in to comment.