|
8 | 8 | """ |
9 | 9 |
|
10 | 10 | import logging |
11 | | -from dataclasses import asdict, dataclass |
| 11 | +from dataclasses import asdict |
12 | 12 | from itertools import groupby |
13 | 13 |
|
14 | 14 | from django.contrib.auth.models import User |
|
34 | 34 | from ..conversations.models import MarkdownNode, RecommendationNode |
35 | 35 | from . import constants as communication_constants |
36 | 36 | from .api import send_email |
| 37 | +from .helpers import NotificationFormatter, normalize_user_name |
37 | 38 |
|
38 | 39 | logger = logging.getLogger("main") |
39 | 40 |
|
@@ -843,187 +844,4 @@ def make_notifications_digest(notifications): |
843 | 844 | ] |
844 | 845 |
|
845 | 846 |
|
846 | | -######################################################################## |
847 | | -# helpers |
848 | | -######################################################################## |
849 | | - |
850 | | - |
851 | | -def normalize_user_name(user): |
852 | | - """Return a user full name or standard greeting by default""" |
853 | | - user_name = f"{user.first_name} {user.last_name}" |
854 | | - if user_name.strip() == "": |
855 | | - user_name = "Madame/Monsieur" |
856 | | - return user_name |
857 | | - |
858 | | - |
859 | | -@dataclass |
860 | | -class FormattedNotification: |
861 | | - summary: str |
862 | | - excerpt: str = None |
863 | | - |
864 | | - |
865 | | -class NotificationFormatter: |
866 | | - """Format notifications for email dispatch""" |
867 | | - |
868 | | - def __init__(self): |
869 | | - self.dispatch_table = { |
870 | | - verbs.Conversation.PRIVATE_MESSAGE: self.format_private_note_created, |
871 | | - verbs.Project.BECAME_ADVISOR: self.format_action_became_advisor, |
872 | | - verbs.Project.BECAME_OBSERVER: self.format_action_became_observer, |
873 | | - verbs.Project.AVAILABLE: self.format_new_project_available, |
874 | | - verbs.Project.SUBMITTED_BY: self.format_project_submitted, |
875 | | - verbs.Recommendation.COMMENTED: self.format_action_commented, |
876 | | - verbs.Recommendation.CREATED: self.format_action_recommended, |
877 | | - verbs.Document.ADDED: self.format_document_uploaded, |
878 | | - } |
879 | | - |
880 | | - def format(self, notification): |
881 | | - """ |
882 | | - Try formatting the notification by the dispatch table or |
883 | | - use the default reprensentation |
884 | | - """ |
885 | | - |
886 | | - def _default(notification): |
887 | | - summary = "{n.actor} {n.verb} {n.action_object}".format(n=notification) |
888 | | - return FormattedNotification(summary=summary) |
889 | | - |
890 | | - fmt = self.dispatch_table.get(notification.verb, _default) |
891 | | - return fmt(notification) |
892 | | - |
893 | | - # ------ Formatter Utils -----# |
894 | | - @staticmethod |
895 | | - def _represent_user(user, is_short=False): |
896 | | - if not user: |
897 | | - fmt = "--compte indisponible--" |
898 | | - return fmt |
899 | | - |
900 | | - if user.last_name: |
901 | | - first_name = ( |
902 | | - f"{user.first_name[:1].capitalize()}." if is_short else user.first_name |
903 | | - ) |
904 | | - fmt = f"{first_name} {user.last_name}" |
905 | | - else: |
906 | | - fmt = f"{user}" |
907 | | - |
908 | | - if user.profile.organization: |
909 | | - fmt += f" ({user.profile.organization.name})" |
910 | | - |
911 | | - return fmt |
912 | | - |
913 | | - @staticmethod |
914 | | - def _represent_recommendation(recommendation): |
915 | | - if recommendation.resource: |
916 | | - return recommendation.resource.title |
917 | | - |
918 | | - return recommendation.intent |
919 | | - |
920 | | - @staticmethod |
921 | | - def _represent_recommendation_excerpt(recommendation): |
922 | | - return recommendation.content[:50] |
923 | | - |
924 | | - @staticmethod |
925 | | - def _represent_project(project): |
926 | | - fmt = f"{project.name}" |
927 | | - if project.commune: |
928 | | - fmt += f" ({project.commune})" |
929 | | - |
930 | | - return fmt |
931 | | - |
932 | | - @staticmethod |
933 | | - def _represent_project_excerpt(project): |
934 | | - if project.description: |
935 | | - return project.description[:50] |
936 | | - |
937 | | - return None |
938 | | - |
939 | | - @staticmethod |
940 | | - def _represent_note_excerpt(note): |
941 | | - return note.content[:200] or None |
942 | | - |
943 | | - @staticmethod |
944 | | - def _represent_followup(followup): |
945 | | - return followup.comment[:50] |
946 | | - |
947 | | - # -------- Routers -----------# |
948 | | - # ------ Real Formatters -----# |
949 | | - def format_private_note_created(self, notification): |
950 | | - """A note was written by a switchtender""" |
951 | | - subject = self._represent_user(notification.actor) |
952 | | - summary = f"{subject} {verbs.Conversation.PRIVATE_MESSAGE}" |
953 | | - excerpt = self._represent_note_excerpt(notification.action_object) |
954 | | - |
955 | | - return FormattedNotification(summary=summary, excerpt=excerpt) |
956 | | - |
957 | | - def format_document_uploaded(self, notification): |
958 | | - """A document was uploaded by a user""" |
959 | | - subject = self._represent_user(notification.actor) |
960 | | - summary = f"{subject} {verbs.Document.ADDED}" |
961 | | - |
962 | | - return FormattedNotification(summary=summary, excerpt=None) |
963 | | - |
964 | | - def format_action_recommended(self, notification): |
965 | | - """An action was recommended by a switchtender""" |
966 | | - subject = self._represent_user(notification.actor) |
967 | | - complement = self._represent_recommendation(notification.action_object) |
968 | | - summary = f"{subject} {verbs.Recommendation.CREATED} '{complement}'" |
969 | | - excerpt = self._represent_recommendation_excerpt(notification.action_object) |
970 | | - |
971 | | - return FormattedNotification(summary=summary, excerpt=excerpt) |
972 | | - |
973 | | - def format_action_commented(self, notification): |
974 | | - """An action was commented by someone""" |
975 | | - subject = self._represent_user(notification.actor) |
976 | | - |
977 | | - if notification.action_object is None: |
978 | | - summary = f"{subject} {verbs.Recommendation.COMMENTED}" |
979 | | - excerpt = "" |
980 | | - else: |
981 | | - complement = self._represent_recommendation(notification.action_object.task) |
982 | | - summary = f"{subject} a commenté la recommandation '{complement}'" |
983 | | - excerpt = self._represent_followup(notification.action_object) |
984 | | - |
985 | | - return FormattedNotification(summary=summary, excerpt=excerpt) |
986 | | - |
987 | | - def format_action_became_switchtender(self, notification): |
988 | | - """Someone joined a project as switchtender""" |
989 | | - subject = self._represent_user(notification.actor) |
990 | | - summary = f"{subject} s'est joint·e à l'équipe de conseil." |
991 | | - |
992 | | - return FormattedNotification(summary=summary, excerpt=None) |
993 | | - |
994 | | - def format_action_became_advisor(self, notification): |
995 | | - """Someone joined a project as advisor""" |
996 | | - subject = self._represent_user(notification.actor) |
997 | | - summary = f"{subject} {verbs.Project.BECAME_ADVISOR}." |
998 | | - |
999 | | - return FormattedNotification(summary=summary, excerpt=None) |
1000 | | - |
1001 | | - def format_action_became_observer(self, notification): |
1002 | | - """Someone joined a project as observer""" |
1003 | | - subject = self._represent_user(notification.actor) |
1004 | | - summary = f"{subject} {verbs.Project.BECAME_OBSERVER}." |
1005 | | - |
1006 | | - return FormattedNotification(summary=summary, excerpt=None) |
1007 | | - |
1008 | | - def format_project_submitted(self, notification): |
1009 | | - """A project was submitted for moderation""" |
1010 | | - subject = self._represent_user(notification.actor) |
1011 | | - complement = self._represent_project(notification.action_object) |
1012 | | - summary = f"{subject} {verbs.Project.SUBMITTED_BY}: '{complement}'" |
1013 | | - |
1014 | | - excerpt = self._represent_project_excerpt(notification.action_object) |
1015 | | - |
1016 | | - return FormattedNotification(summary=summary, excerpt=excerpt) |
1017 | | - |
1018 | | - def format_new_project_available(self, notification): |
1019 | | - """A new project is now available""" |
1020 | | - subject = self._represent_user(notification.actor) |
1021 | | - complement = self._represent_project(notification.action_object) |
1022 | | - summary = f"{subject} {verbs.Project.AVAILABLE} '{complement}'" |
1023 | | - |
1024 | | - excerpt = self._represent_project_excerpt(notification.action_object) |
1025 | | - |
1026 | | - return FormattedNotification(summary=summary, excerpt=excerpt) |
1027 | | - |
1028 | | - |
1029 | 847 | # eof |
0 commit comments