37 from django.core import urlresolvers |
37 from django.core import urlresolvers |
38 from django.utils.translation import ugettext |
38 from django.utils.translation import ugettext |
39 |
39 |
40 from soc.logic import accounts |
40 from soc.logic import accounts |
41 from soc.logic import dicts |
41 from soc.logic import dicts |
|
42 from soc.logic import rights as rights_logic |
42 from soc.logic.models.club_admin import logic as club_admin_logic |
43 from soc.logic.models.club_admin import logic as club_admin_logic |
|
44 from soc.logic.models.club_member import logic as club_member_logic |
43 from soc.logic.models.document import logic as document_logic |
45 from soc.logic.models.document import logic as document_logic |
44 from soc.logic.models.host import logic as host_logic |
46 from soc.logic.models.host import logic as host_logic |
45 from soc.logic.models.notification import logic as notification_logic |
47 from soc.logic.models.notification import logic as notification_logic |
46 from soc.logic.models.request import logic as request_logic |
48 from soc.logic.models.request import logic as request_logic |
47 from soc.logic.models.role import logic as role_logic |
49 from soc.logic.models.role import logic as role_logic |
66 DEF_DEV_LOGOUT_LOGIN_MSG_FMT = ugettext( |
68 DEF_DEV_LOGOUT_LOGIN_MSG_FMT = ugettext( |
67 'Please <a href="%%(sign_out)s">sign out</a>' |
69 'Please <a href="%%(sign_out)s">sign out</a>' |
68 ' and <a href="%%(sign_in)s">sign in</a>' |
70 ' and <a href="%%(sign_in)s">sign in</a>' |
69 ' again as %(role)s to view this page.') |
71 ' again as %(role)s to view this page.') |
70 |
72 |
|
73 DEF_NEED_MEMBERSHIP_MSG_FMT = ugettext( |
|
74 'You need to be in the %(status)s group to %(action)s' |
|
75 ' documents in the %(prefix)s prefix.') |
|
76 |
71 DEF_PAGE_DENIED_MSG = ugettext( |
77 DEF_PAGE_DENIED_MSG = ugettext( |
72 'Access to this page has been restricted') |
78 'Access to this page has been restricted') |
73 |
79 |
74 DEF_LOGOUT_MSG_FMT = ugettext( |
80 DEF_LOGOUT_MSG_FMT = ugettext( |
75 'Please <a href="%(sign_out)s">sign out</a> in order to view this page') |
81 'Please <a href="%(sign_out)s">sign out</a> in order to view this page') |
132 The __setitem__() and __getitem__() methods are overloaded to DTRT |
138 The __setitem__() and __getitem__() methods are overloaded to DTRT |
133 when adding new access rights, and retrieving them, so use these |
139 when adding new access rights, and retrieving them, so use these |
134 rather then modifying rights directly if so desired. |
140 rather then modifying rights directly if so desired. |
135 """ |
141 """ |
136 |
142 |
|
143 MEMBERSHIP = { |
|
144 'anyone': 'allow', |
|
145 'club_admin': 'checkIsClubAdminForScope', |
|
146 'club_member': 'checkIsClubMemberForScope', |
|
147 'host': 'checkHasHostEntity', |
|
148 'org_admin': 'deny', |
|
149 'org_mentor': 'deny', |
|
150 'org_student': 'deny', |
|
151 'user': 'checkIsUser', |
|
152 'user_self': 'checkIsUserSelf', |
|
153 } |
|
154 |
137 def __init__(self, params): |
155 def __init__(self, params): |
138 """Adopts base.rights as rights if base is set. |
156 """Adopts base.rights as rights if base is set. |
139 """ |
157 """ |
140 |
158 |
141 base = params.get('rights') if params else None |
159 base = params.get('rights') if params else None |
271 return |
289 return |
272 |
290 |
273 for checker_name, args in self[access_type]: |
291 for checker_name, args in self[access_type]: |
274 self.check(use_cache, checker_name, django_args, args) |
292 self.check(use_cache, checker_name, django_args, args) |
275 |
293 |
|
294 def checkMembership(self, action, prefix, status, django_args): |
|
295 """Checks whether the user has access to the specified status. |
|
296 |
|
297 Args: |
|
298 action: the action that was performed (e.g., 'read') |
|
299 prefix: the prefix, determines what access set is used |
|
300 status: the access status (e.g., 'public') |
|
301 django_args: the django args to pass on to the checkers |
|
302 """ |
|
303 |
|
304 checker = rights_logic.Checker(prefix) |
|
305 roles = checker.getMembership(status) |
|
306 |
|
307 message_fmt = DEF_NEED_MEMBERSHIP_MSG_FMT % { |
|
308 'action': action, |
|
309 'prefix': prefix, |
|
310 'status': status, |
|
311 } |
|
312 |
|
313 # try to see if they belong to any of the roles, if not, raise an |
|
314 # access violation for the specified action, prefix and status. |
|
315 for role in roles: |
|
316 try: |
|
317 checker_name = self.MEMBERSHIP[role] |
|
318 self.doCheck(checker_name, django_args, []) |
|
319 |
|
320 # the check passed, we can stop now |
|
321 break |
|
322 except out_of_band.Error: |
|
323 continue |
|
324 else: |
|
325 raise out_of_band.AccessViolation(message_fmt) |
|
326 |
|
327 |
276 def allow(self, django_args): |
328 def allow(self, django_args): |
277 """Never raises an alternate HTTP response. (an access no-op, basically). |
329 """Never raises an alternate HTTP response. (an access no-op, basically). |
278 |
330 |
279 Args: |
331 Args: |
280 django_args: a dictionary with django's arguments |
332 django_args: a dictionary with django's arguments |
354 # agreesToSiteToS() call above always returns True if no ToS is in effect. |
406 # agreesToSiteToS() call above always returns True if no ToS is in effect. |
355 login_msg_fmt = DEF_AGREE_TO_TOS_MSG_FMT % { |
407 login_msg_fmt = DEF_AGREE_TO_TOS_MSG_FMT % { |
356 'tos_link': redirects.getToSRedirect(site_logic.getSingleton())} |
408 'tos_link': redirects.getToSRedirect(site_logic.getSingleton())} |
357 |
409 |
358 raise out_of_band.LoginRequest(message_fmt=login_msg_fmt) |
410 raise out_of_band.LoginRequest(message_fmt=login_msg_fmt) |
359 |
411 |
|
412 @allowDeveloper |
|
413 def checkIsUserSelf(self, django_args): |
|
414 """Checks whether the specified user is the logged in user |
|
415 |
|
416 Args: |
|
417 django_args: the keyword args from django, only scope_path is used |
|
418 """ |
|
419 |
|
420 if not 'scope_path' in django_args: |
|
421 self.deny(django_args) |
|
422 |
|
423 if self.user.link_id == django_args['scope_path']: |
|
424 return |
|
425 |
|
426 raise out_of_band.AccessViolation() |
|
427 |
360 def checkIsUnusedAccount(self, django_args): |
428 def checkIsUnusedAccount(self, django_args): |
361 """Raises an alternate HTTP response if Google Account has a User entity. |
429 """Raises an alternate HTTP response if Google Account has a User entity. |
362 |
430 |
363 Args: |
431 Args: |
364 django_args: a dictionary with django's arguments |
432 django_args: a dictionary with django's arguments |
591 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
659 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
592 'role': 'a Program Administrator '} |
660 'role': 'a Program Administrator '} |
593 |
661 |
594 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
662 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
595 |
663 |
|
664 def checkHasHostEntity(self, django_args): |
|
665 """Checks whether the current user has a Host entity. |
|
666 """ |
|
667 |
|
668 self.checkIsHost({}) |
|
669 |
596 @denySidebar |
670 @denySidebar |
597 @allowDeveloper |
671 @allowDeveloper |
598 def checkIsHostForProgram(self, django_args): |
672 def checkIsHostForProgram(self, django_args): |
599 """Checks if the user is a host for the specified program. |
673 """Checks if the user is a host for the specified program. |
600 """ |
674 """ |
686 'role': 'a Club Admin for this Club'} |
760 'role': 'a Club Admin for this Club'} |
687 |
761 |
688 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
762 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
689 |
763 |
690 @allowDeveloper |
764 @allowDeveloper |
|
765 @allowIfCheckPasses('checkIsClubAdminForClub') |
|
766 def checkIsClubMemberForClub(self, django_args): |
|
767 """Returns an alternate HTTP response if Google Account has no Club Member |
|
768 entity for the specified club. |
|
769 |
|
770 Args: |
|
771 django_args: a dictionary with django's arguments |
|
772 |
|
773 Raises: |
|
774 AccessViolationResponse: if the required authorization is not met |
|
775 |
|
776 Returns: |
|
777 None if Club Member exists for the specified club, or a subclass of |
|
778 django.http.HttpResponse which contains the alternate response |
|
779 should be returned by the calling view. |
|
780 """ |
|
781 |
|
782 self.checkIsUser(django_args) |
|
783 |
|
784 if django_args.get('scope_path'): |
|
785 scope_path = django_args['scope_path'] |
|
786 else: |
|
787 scope_path = django_args['link_id'] |
|
788 |
|
789 fields = {'user': self.user, |
|
790 'scope_path': scope_path, |
|
791 'status': 'active'} |
|
792 |
|
793 club_member_entity = club_member_logic.getForFields(fields, unique=True) |
|
794 |
|
795 if club_member_entity: |
|
796 return |
|
797 |
|
798 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
799 'role': 'a Club Member for this Club'} |
|
800 |
|
801 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
802 |
|
803 def checkIsClubAdminForScope(self, django_args): |
|
804 """Checks whether the current user is a Club Mdmin. |
|
805 |
|
806 Args: |
|
807 django_args: the keyword arguments from django, only scope_path is used |
|
808 """ |
|
809 |
|
810 scope_path = django_args['scope_path'] |
|
811 self.checkIsClubAdminForClub({'link_id': scope_path}) |
|
812 |
|
813 def checkIsClubMemberForScope(self, django_args): |
|
814 """Checks whether the current user is a Club Mdmin. |
|
815 |
|
816 Args: |
|
817 django_args: the keyword arguments from django, only scope_path is used |
|
818 """ |
|
819 |
|
820 scope_path = django_args['scope_path'] |
|
821 self.checkIsClubMemberForClub({'link_id': scope_path}) |
|
822 |
|
823 @allowDeveloper |
691 def checkIsApplicationAccepted(self, django_args, app_logic): |
824 def checkIsApplicationAccepted(self, django_args, app_logic): |
692 """Returns an alternate HTTP response if Google Account has no Club App |
825 """Returns an alternate HTTP response if Google Account has no Club App |
693 entity for the specified Club. |
826 entity for the specified Club. |
694 |
827 |
695 Args: |
828 Args: |
881 #TODO(SRabbelier) inform user that return_url and field are required |
1014 #TODO(SRabbelier) inform user that return_url and field are required |
882 self.deny(django_args) |
1015 self.deny(django_args) |
883 |
1016 |
884 @denySidebar |
1017 @denySidebar |
885 @allowDeveloper |
1018 @allowDeveloper |
886 def checkIsDocumentPublic(self, django_args): |
1019 def checkIsDocumentReadable(self, django_args): |
887 """Checks whether a document is public. |
1020 """Checks whether a document is readable. |
888 |
1021 |
889 Args: |
1022 Args: |
890 django_args: a dictionary with django's arguments |
1023 django_args: a dictionary with django's arguments |
891 """ |
1024 """ |
892 |
1025 |
893 key_fields = document_logic.getKeyFieldsFromFields(django_args) |
1026 key_fields = document_logic.getKeyFieldsFromFields(django_args) |
894 document_logic.getFromKeyFields(key_fields) |
1027 document = document_logic.getFromKeyFields(key_fields) |
|
1028 |
|
1029 self.checkMembership('read', document.prefix, |
|
1030 document.read_access, django_args) |
|
1031 |
|
1032 @denySidebar |
|
1033 @allowDeveloper |
|
1034 def checkIsDocumentWritable(self, django_args): |
|
1035 """Checks whether a document is writable. |
|
1036 |
|
1037 Args: |
|
1038 django_args: a dictionary with django's arguments |
|
1039 """ |
|
1040 |
|
1041 key_fields = document_logic.getKeyFieldsFromFields(django_args) |
|
1042 document = document_logic.getFromKeyFields(key_fields) |
|
1043 |
|
1044 self.checkMembership('write', document.prefix, |
|
1045 document.write_access, django_args) |
895 |
1046 |
896 @allowIfCheckPasses('checkIsHostForProgram') |
1047 @allowIfCheckPasses('checkIsHostForProgram') |
897 def checkIsProgramVisible(self, django_args): |
1048 def checkIsProgramVisible(self, django_args): |
898 """Checks whether a program is visible. |
1049 """Checks whether a program is visible. |
899 """ |
1050 """ |
917 'role': ugettext('a Program Administrator')} |
1068 'role': ugettext('a Program Administrator')} |
918 |
1069 |
919 raise out_of_band.AccessViolation(DEF_DEV_LOGOUT_LOGIN_MSG_FMT, |
1070 raise out_of_band.AccessViolation(DEF_DEV_LOGOUT_LOGIN_MSG_FMT, |
920 context=context) |
1071 context=context) |
921 |
1072 |
922 |
|
923 def checkCanEditTimeline(self, django_args): |
1073 def checkCanEditTimeline(self, django_args): |
924 """Allows developers and hosts for this program's timeline to edit it. |
1074 """Checks whether this program's timeline may be edited. |
925 """ |
1075 """ |
|
1076 |
926 time_line_keyname = django_args['scope_path'] |
1077 time_line_keyname = django_args['scope_path'] |
927 timeline_entity = timeline_logic.getFromKeyName(time_line_keyname) |
1078 timeline_entity = timeline_logic.getFromKeyName(time_line_keyname) |
928 |
1079 |
929 if not timeline_entity: |
1080 if not timeline_entity: |
930 # timeline does not exists so deny |
1081 # timeline does not exists so deny |