11import sys
22import yaml
3- from django .apps import apps
43from waffle import switch_is_active
54from osf import features
65
1918 'email_transactional' : 'instantly' ,
2019}
2120
22- def populate_notification_types (* args , ** kwargs ):
21+ def populate_notification_types (* args , restore_one = None , restore_all = False , ** kwargs ):
2322 if kwargs .get ('sender' ): # exists when called as a post_migrate signal
2423 if not switch_is_active (features .POPULATE_NOTIFICATION_TYPES ):
2524 if 'pytest' not in sys .modules :
@@ -28,64 +27,89 @@ def populate_notification_types(*args, **kwargs):
2827 logger .info ('Populating notification types...' )
2928 from django .contrib .contenttypes .models import ContentType
3029 from osf .models .notification_type import NotificationType
30+
3131 try :
3232 with open (settings .NOTIFICATION_TYPES_YAML ) as stream :
3333 notification_types = yaml .safe_load (stream )
34- for notification_type in notification_types ['notification_types' ]:
35- notification_type .pop ('__docs__' , None )
36- notification_type .pop ('tests' , None )
37- object_content_type_model_name = notification_type .pop ('object_content_type_model_name' )
34+
35+ notification_types_dict = {
36+ nt ['name' ]: nt for nt in notification_types ['notification_types' ]
37+ }
38+
39+ all_names = set (notification_types_dict .keys ())
40+ existing_names = set (
41+ NotificationType .objects .values_list ('name' , flat = True )
42+ )
43+
44+ if restore_one :
45+ if restore_one not in notification_types_dict :
46+ raise ValueError (f'Notification type "{ restore_one } " not found in YAML' )
47+ names_to_process = {restore_one }
48+
49+ elif restore_all :
50+ names_to_process = all_names
51+
52+ else :
53+ names_to_process = all_names - existing_names
54+
55+ logger .info (f'Processing { len (names_to_process )} notification types' )
56+
57+ for name in names_to_process :
58+ raw_nt = notification_types_dict [name ].copy ()
59+
60+ raw_nt .pop ('__docs__' , None )
61+ raw_nt .pop ('tests' , None )
62+
63+ object_content_type_model_name = raw_nt .pop ('object_content_type_model_name' )
3864
3965 if object_content_type_model_name == 'desk' :
4066 content_type = None
41- elif object_content_type_model_name == 'osfuser' :
42- OSFUser = apps .get_model ('osf' , 'OSFUser' )
43- content_type = ContentType .objects .get_for_model (OSFUser )
44- elif object_content_type_model_name == 'preprint' :
45- Preprint = apps .get_model ('osf' , 'Preprint' )
46- content_type = ContentType .objects .get_for_model (Preprint )
47- elif object_content_type_model_name == 'collectionsubmission' :
48- CollectionSubmission = apps .get_model ('osf' , 'CollectionSubmission' )
49- content_type = ContentType .objects .get_for_model (CollectionSubmission )
50- elif object_content_type_model_name == 'abstractprovider' :
51- AbstractProvider = apps .get_model ('osf' , 'abstractprovider' )
52- content_type = ContentType .objects .get_for_model (AbstractProvider )
53- elif object_content_type_model_name == 'osfuser' :
54- OSFUser = apps .get_model ('osf' , 'OSFUser' )
55- content_type = ContentType .objects .get_for_model (OSFUser )
56- elif object_content_type_model_name == 'draftregistration' :
57- DraftRegistration = apps .get_model ('osf' , 'DraftRegistration' )
58- content_type = ContentType .objects .get_for_model (DraftRegistration )
5967 else :
6068 try :
61- content_type = ContentType .objects .get (
62- app_label = 'osf' ,
63- model = object_content_type_model_name
64- )
69+ content_type = ContentType .objects .get_by_natural_key (app_label = 'osf' , model = object_content_type_model_name )
6570 except ContentType .DoesNotExist :
6671 raise ValueError (f'No content type for osf.{ object_content_type_model_name } ' )
6772
68- template_path = notification_type .pop ('template' )
73+ template_path = raw_nt .pop ('template' )
74+ template = None
75+
6976 if template_path :
7077 with open (template_path ) as stream :
7178 template = stream .read ()
7279
7380 nt , _ = NotificationType .objects .update_or_create (
74- name = notification_type [ ' name' ] ,
75- defaults = notification_type ,
81+ name = name ,
82+ defaults = raw_nt ,
7683 )
84+
7785 nt .object_content_type = content_type
78- if not nt . template or settings . DEV_MODE :
86+ if template :
7987 nt .template = template
88+
8089 nt .save ()
90+
8191 except ProgrammingError :
8292 logger .info ('Notification types failed potential side effect of reverse migration' )
8393 logger .info ('Finished populating notification types.' )
8494
85-
8695class Command (BaseCommand ):
87- help = 'Population notification types.'
96+ help = 'Populate notification types.'
97+
98+ def add_arguments (self , parser ):
99+ parser .add_argument (
100+ '--restore-all' ,
101+ action = 'store_true' ,
102+ help = 'Restore all templates from files'
103+ )
104+ parser .add_argument (
105+ '--restore' ,
106+ type = str ,
107+ help = 'Restore specific template by name'
108+ )
88109
89110 def handle (self , * args , ** options ):
90111 with transaction .atomic ():
91- populate_notification_types (args , options )
112+ populate_notification_types (
113+ restore_all = options ['restore_all' ],
114+ restore_one = options ['restore' ]
115+ )
0 commit comments