class ExternalAccount(base.ObjectIDMixin, base.BaseModel): """An account on an external service. Note that this object is not and should not be aware of what other objects are associated with it. This is by design, and this object should be kept as thin as possible, containing only those fields that must be stored in the database. The ``provider`` field is a de facto foreign key to an ``ExternalProvider`` object, as providers are not stored in the database. """ # The OAuth credentials. One or both of these fields should be populated. # For OAuth1, this is usually the "oauth_token" # For OAuth2, this is usually the "access_token" oauth_key = EncryptedTextField(blank=True, null=True) # For OAuth1, this is usually the "oauth_token_secret" # For OAuth2, this is not used oauth_secret = EncryptedTextField(blank=True, null=True) # Used for OAuth2 only refresh_token = EncryptedTextField(blank=True, null=True) date_last_refreshed = NonNaiveDateTimeField(blank=True, null=True) expires_at = NonNaiveDateTimeField(blank=True, null=True) scopes = ArrayField(models.CharField(max_length=128), default=list, blank=True) # The `name` of the service # This lets us query for only accounts on a particular provider # TODO We should make provider an actual FK someday. provider = models.CharField(max_length=50, blank=False, null=False) # The proper 'name' of the service # Needed for account serialization provider_name = models.CharField(max_length=255, blank=False, null=False) # The unique, persistent ID on the remote service. provider_id = models.CharField(max_length=255, blank=False, null=False) # The user's name on the external service display_name = EncryptedTextField(blank=True, null=True) # A link to the user's profile on the external service profile_url = EncryptedTextField(blank=True, null=True) def __repr__(self): return '<ExternalAccount: {}/{}>'.format(self.provider, self.provider_id) def _natural_key(self): if self.pk: return self.pk return hash(str(self.provider_id) + str(self.provider)) class Meta: unique_together = [( 'provider', 'provider_id', )]
class RdmAnnouncementOption(BaseModel): user = models.ForeignKey('OSFUser', null=True) twitter_api_key = EncryptedTextField(blank=True, null=True) twitter_api_secret = EncryptedTextField(blank=True, null=True) twitter_access_token = EncryptedTextField(blank=True, null=True) twitter_access_token_secret = EncryptedTextField(blank=True, null=True) facebook_api_key = EncryptedTextField(blank=True, null=True) facebook_api_secret = EncryptedTextField(blank=True, null=True) facebook_access_token = EncryptedTextField(blank=True, null=True) redmine_api_url = EncryptedTextField(blank=True, null=True) redmine_api_key = EncryptedTextField(blank=True, null=True)
class PreprintProvider(ObjectIDMixin, BaseModel): PUSH_SHARE_TYPE_CHOICES = (('Preprint', 'Preprint'), ('Thesis', 'Thesis'),) PUSH_SHARE_TYPE_HELP = 'This SHARE type will be used when pushing publications to SHARE' name = models.CharField(null=False, max_length=128) # max length on prod: 22 description = models.TextField(default='', blank=True) domain = models.URLField(blank=True, default='', max_length=200) domain_redirect_enabled = models.BooleanField(default=False) external_url = models.URLField(null=True, blank=True, max_length=200) # max length on prod: 25 email_contact = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 email_support = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 example = models.CharField(null=True, blank=True, max_length=20) # max length on prod: 5 access_token = EncryptedTextField(null=True, blank=True) advisory_board = models.TextField(default='', blank=True) social_twitter = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_facebook = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_instagram = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 footer_links = models.TextField(default='', blank=True) share_publish_type = models.CharField(choices=PUSH_SHARE_TYPE_CHOICES, default='Preprint', help_text=PUSH_SHARE_TYPE_HELP, max_length=32) share_source = models.CharField(blank=True, max_length=200) share_title = models.TextField(default='', blank=True) allow_submissions = models.BooleanField(default=True) additional_providers = fields.ArrayField(models.CharField(max_length=200), default=list, blank=True) PREPRINT_WORD_CHOICES = ( ('preprint', 'Preprint'), ('paper', 'Paper'), ('thesis', 'Thesis'), ('none', 'None') ) preprint_word = models.CharField(max_length=10, choices=PREPRINT_WORD_CHOICES, default='preprint') subjects_acceptable = DateTimeAwareJSONField(blank=True, default=list) licenses_acceptable = models.ManyToManyField(NodeLicense, blank=True, related_name='licenses_acceptable') default_license = models.ForeignKey(NodeLicense, blank=True, related_name='default_license', null=True) class Meta: # custom permissions for use in the OSF Admin App permissions = ( ('view_preprintprovider', 'Can view preprint provider details'), ) def __unicode__(self): return '{} with id {}'.format(self.name, self.id) @property def highlighted_subjects(self): if self.subjects.filter(highlighted=True).exists(): return self.subjects.filter(highlighted=True).order_by('text')[:10] else: return sorted(self.top_level_subjects, key=lambda s: s.text)[:10] @property def top_level_subjects(self): if self.subjects.exists(): return self.subjects.filter(parent__isnull=True) else: # TODO: Delet this when all PreprintProviders have a mapping if len(self.subjects_acceptable) == 0: return Subject.objects.filter(parent__isnull=True, provider___id='osf') tops = set([sub[0][0] for sub in self.subjects_acceptable]) return [Subject.load(sub) for sub in tops] @property def all_subjects(self): if self.subjects.exists(): return self.subjects.all() else: # TODO: Delet this when all PreprintProviders have a mapping return rules_to_subjects(self.subjects_acceptable) def get_absolute_url(self): return '{}preprint_providers/{}'.format(self.absolute_api_v2_url, self._id) @property def absolute_api_v2_url(self): path = '/preprint_providers/{}/'.format(self._id) return api_v2_url(path)
def field(self): return EncryptedTextField(null=True, blank=True)
class RdmFcmDevice(BaseModel): user = models.ForeignKey('OSFUser', null=True) device_token = EncryptedTextField(blank=True, null=True) date_created = NonNaiveDateTimeField(auto_now_add=True)
class PreprintProvider(AbstractProvider): PUSH_SHARE_TYPE_CHOICES = ( ('Preprint', 'Preprint'), ('Thesis', 'Thesis'), ) PUSH_SHARE_TYPE_HELP = 'This SHARE type will be used when pushing publications to SHARE' REVIEWABLE_RELATION_NAME = 'preprint_services' share_publish_type = models.CharField(choices=PUSH_SHARE_TYPE_CHOICES, default='Preprint', help_text=PUSH_SHARE_TYPE_HELP, max_length=32) share_source = models.CharField(blank=True, max_length=200) share_title = models.TextField(default='', blank=True) additional_providers = fields.ArrayField(models.CharField(max_length=200), default=list, blank=True) access_token = EncryptedTextField(null=True, blank=True) doi_prefix = models.CharField(blank=True, max_length=32) PREPRINT_WORD_CHOICES = (('preprint', 'Preprint'), ('paper', 'Paper'), ('thesis', 'Thesis'), ('work', 'Work'), ('none', 'None')) preprint_word = models.CharField(max_length=10, choices=PREPRINT_WORD_CHOICES, default='preprint') subjects_acceptable = DateTimeAwareJSONField(blank=True, default=list) class Meta: permissions = ( # custom permissions for use in the OSF Admin App ('view_preprintprovider', 'Can view preprint provider details'), ) @property def readable_type(self): return 'preprint' @property def all_subjects(self): if self.subjects.exists(): return self.subjects.all() else: # TODO: Delet this when all PreprintProviders have a mapping return rules_to_subjects(self.subjects_acceptable) @property def has_highlighted_subjects(self): return self.subjects.filter(highlighted=True).exists() @property def highlighted_subjects(self): if self.has_highlighted_subjects: return self.subjects.filter(highlighted=True).order_by('text')[:10] else: return sorted(self.top_level_subjects, key=lambda s: s.text)[:10] @property def top_level_subjects(self): if self.subjects.exists(): return optimize_subject_query( self.subjects.filter(parent__isnull=True)) else: # TODO: Delet this when all PreprintProviders have a mapping if len(self.subjects_acceptable) == 0: return optimize_subject_query( Subject.objects.filter(parent__isnull=True, provider___id='osf')) tops = set([sub[0][0] for sub in self.subjects_acceptable]) return [Subject.load(sub) for sub in tops] @property def landing_url(self): return self.domain if self.domain else '{}preprints/{}'.format( settings.DOMAIN, self._id) def get_absolute_url(self): return '{}preprint_providers/{}'.format(self.absolute_api_v2_url, self._id) @property def absolute_api_v2_url(self): path = '/providers/preprints/{}/'.format(self._id) return api_v2_url(path)
class PreprintProvider(ObjectIDMixin, BaseModel): name = models.CharField(null=False, max_length=128) # max length on prod: 22 logo_name = models.CharField(null=True, blank=True, max_length=128) # max length on prod: 17 header_text = models.TextField(default='', blank=True) description = models.CharField(null=True, blank=True, max_length=256) # max length on prod: 56 banner_name = models.CharField(null=True, blank=True, max_length=128) # max length on prod: 19 external_url = models.URLField(null=True, blank=True, max_length=200) # max length on prod: 25 email_contact = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 email_support = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 example = models.CharField(null=True, blank=True, max_length=20) # max length on prod: 5 access_token = EncryptedTextField(null=True, blank=True) advisory_board = models.TextField(null=True, blank=True) social_twitter = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_facebook = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_instagram = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 subjects_acceptable = DateTimeAwareJSONField(blank=True, default=list) licenses_acceptable = models.ManyToManyField(NodeLicense, blank=True) def __unicode__(self): return '{} with id {}'.format(self.name, self.id) @property def top_level_subjects(self): if len(self.subjects_acceptable) == 0: return Subject.find(Q('parents', 'isnull', True)) tops = set([sub[0][0] for sub in self.subjects_acceptable]) return [Subject.load(sub) for sub in tops] @property def all_subjects(self): q = [] for rule in self.subjects_acceptable: if rule[1]: q.append(Q('parents', 'eq', Subject.load(rule[0][-1]))) if len(rule[0]) == 1: potential_parents = Subject.find(Q('parents', 'eq', Subject.load(rule[0][-1]))) for parent in potential_parents: q.append(Q('parents', 'eq', parent)) for sub in rule[0]: q.append(Q('_id', 'eq', sub)) return Subject.find(reduce(lambda x, y: x | y, q)) if len(q) > 1 else (Subject.find(q[0]) if len(q) else Subject.find()) def get_absolute_url(self): return '{}preprint_providers/{}'.format(self.absolute_api_v2_url, self._id) @property def absolute_api_v2_url(self): path = '/preprint_providers/{}/'.format(self._id) return api_v2_url(path) @property def logo_path(self): if self.logo_name: return '/static/img/preprint_providers/{}'.format(self.logo_name) else: return None @property def banner_path(self): if self.logo_name: return '/static/img/preprint_providers/{}'.format(self.logo_name) else: return None
class AbstractProvider(TypedModel, TypedObjectIDMixin, ReviewProviderMixin, DirtyFieldsMixin, BaseModel): class Meta: unique_together = ('_id', 'type') permissions = REVIEW_PERMISSIONS PUSH_SHARE_TYPE_CHOICES = ( ('Preprint', 'Preprint'), ('Thesis', 'Thesis'), ('Registration', 'Registration'), ) PUSH_SHARE_TYPE_HELP = 'This SHARE type will be used when pushing publications to SHARE' default__id = 'osf' @classmethod def get_default(cls): return cls.objects.get(_id=cls.default__id) @property def is_default(self): return self._id == self.default__id @classmethod def update_or_create_from_json(cls, provider_data, user): licenses = [ NodeLicense.objects.get(license_id=license_id) for license_id in provider_data.pop('licenses_acceptable', []) ] default_license = provider_data.pop('default_license', False) provider_data.pop('additional_providers', False) subject_data = provider_data.pop('subjects', False) brand = None if provider_data.get('brand'): try: brand = Brand.objects.get(id=provider_data.pop('brand')) except Brand.DoesNotExist: # JSON is old or imported from staging etc. pass if provider_data.get( 'id'): # <- determines if creating new or updating provider = cls.objects.get(id=provider_data.pop('id')) else: provider = cls(**provider_data) if provider._perform_unique_checks([(AbstractProvider, ('_id', 'type'))]): provider_data.pop( '_id' ) # these must be unique, but catch and remove and allow for UX provider = cls(**provider_data) provider._creator = user provider.save() if brand: provider.brand = brand if licenses: provider.licenses_acceptable.set(licenses) if default_license: provider.default_license = NodeLicense.objects.get( license_id=default_license) # Only adds the JSON taxonomy if there is no existing taxonomy data if subject_data and not provider.subjects.count(): # circular import from osf.management.commands.populate_custom_taxonomies import migrate as add_subjects add_subjects(provider=provider._id, data=subject_data if isinstance(subject_data, dict) else json.loads(subject_data), dry_run=False) # Collections only code primary_collection = provider_data.pop('primary_collection', None) if primary_collection: provider.primary_collection.collected_type_choices = primary_collection[ 'fields']['collected_type_choices'] provider.primary_collection.status_choices = primary_collection[ 'fields']['status_choices'] provider.primary_collection.issue_choices = primary_collection[ 'fields']['issue_choices'] provider.primary_collection.volume_choices = primary_collection[ 'fields']['volume_choices'] provider.primary_collection.program_area_choices = primary_collection[ 'fields']['program_area_choices'] provider.primary_collection.save() return provider primary_collection = models.ForeignKey('Collection', related_name='+', null=True, blank=True, on_delete=models.SET_NULL) name = models.CharField(null=False, max_length=128) # max length on prod: 22 advisory_board = models.TextField(default='', blank=True) description = models.TextField(default='', blank=True) domain = models.URLField(blank=True, default='', max_length=200) domain_redirect_enabled = models.BooleanField(default=False) external_url = models.URLField(null=True, blank=True, max_length=200) # max length on prod: 25 email_contact = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 email_support = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 social_twitter = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_facebook = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_instagram = models.CharField( null=True, blank=True, max_length=200) # max length on prod: 8 footer_links = models.TextField(default='', blank=True) facebook_app_id = models.BigIntegerField(blank=True, null=True) example = models.CharField(null=True, blank=True, max_length=20) # max length on prod: 5 licenses_acceptable = models.ManyToManyField( NodeLicense, blank=True, related_name='licenses_acceptable') default_license = models.ForeignKey(NodeLicense, related_name='default_license', null=True, blank=True, on_delete=models.CASCADE) allow_submissions = models.BooleanField(default=True) allow_commenting = models.BooleanField(default=False) access_token = EncryptedTextField(null=True, blank=True) brand = models.ForeignKey('Brand', related_name='providers', null=True, blank=True, on_delete=models.SET_NULL) branded_discovery_page = models.BooleanField(default=True) advertises_on_discovery = models.BooleanField(default=True) has_landing_page = models.BooleanField(default=False) share_publish_type = models.CharField(choices=PUSH_SHARE_TYPE_CHOICES, help_text=PUSH_SHARE_TYPE_HELP, default='Thesis', max_length=32) share_source = models.CharField(blank=True, default='', max_length=200) share_title = models.TextField(default='', blank=True) doi_prefix = models.CharField(blank=True, null=True, max_length=32) def __repr__(self): return ( '(name={self.name!r}, default_license={self.default_license!r}, ' 'allow_submissions={self.allow_submissions!r}) with id {self.id!r}' ).format(self=self) def __str__(self): return '[{}] {} - {}'.format(self.readable_type, self.name, self.id) @property def all_subjects(self): if self.subjects.exists(): return self.subjects.all() return Subject.objects.filter( provider___id='osf', provider__type='osf.preprintprovider', ) @property def has_highlighted_subjects(self): return self.subjects.filter(highlighted=True).exists() @property def highlighted_subjects(self): if self.has_highlighted_subjects: return self.subjects.filter(highlighted=True).order_by('text')[:10] else: return sorted(self.top_level_subjects, key=lambda s: s.text)[:10] @property def top_level_subjects(self): if self.subjects.exists(): return optimize_subject_query( self.subjects.filter(parent__isnull=True)) return optimize_subject_query( Subject.objects.filter( parent__isnull=True, provider___id='osf', provider__type='osf.preprintprovider', )) @property def readable_type(self): raise NotImplementedError def get_asset_url(self, name): """ Helper that returns an associated ProviderAssetFile's url, or None :param str name: Name to perform lookup by :returns str|None: url of file """ try: return self.asset_files.get(name=name).file.url except ProviderAssetFile.DoesNotExist: return None def setup_share_source(self, provider_home_page): if self.access_token: raise ValidationError( 'Cannot update access_token because one or the other already exists' ) if not settings.SHARE_ENABLED or not settings.SHARE_URL: raise ValidationError('SHARE_ENABLED is set to false') if not self.get_asset_url('square_color_no_transparent'): raise ValidationError( 'Unable to find "square_color_no_transparent" icon for provider' ) if settings.SHARE_PROVIDER_PREPEND: share_provider_name = f'{settings.SHARE_PROVIDER_PREPEND}_{self.name}' else: share_provider_name = self.name resp = requests.post( f'{settings.SHARE_URL}api/v2/sources/', json={ 'data': { 'type': 'Source', 'attributes': { 'homePage': provider_home_page, 'longTitle': share_provider_name, 'iconUrl': self.get_asset_url('square_color_no_transparent') } } }, headers={ 'Authorization': f'Bearer {settings.SHARE_API_TOKEN}', 'Content-Type': 'application/vnd.api+json' }) resp.raise_for_status() resp_json = resp.json() self.share_source = resp_json['data']['attributes']['longTitle'] for data in resp_json['included']: if data['type'] == 'ShareUser': self.access_token = data['attributes']['token'] self.save()
class AbstractProvider(TypedModel, TypedObjectIDMixin, ReviewProviderMixin, DirtyFieldsMixin, BaseModel): class Meta: unique_together = ('_id', 'type') permissions = REVIEW_PERMISSIONS PUSH_SHARE_TYPE_CHOICES = ( ('Preprint', 'Preprint'), ('Thesis', 'Thesis'), ('Registration', 'Registration'), ) PUSH_SHARE_TYPE_HELP = 'This SHARE type will be used when pushing publications to SHARE' default__id = 'osf' @classmethod def get_default(cls): return cls.objects.get(_id=cls.default__id) primary_collection = models.ForeignKey('Collection', related_name='+', null=True, blank=True, on_delete=models.SET_NULL) name = models.CharField(null=False, max_length=128) # max length on prod: 22 advisory_board = models.TextField(default='', blank=True) description = models.TextField(default='', blank=True) domain = models.URLField(blank=True, default='', max_length=200) domain_redirect_enabled = models.BooleanField(default=False) external_url = models.URLField(null=True, blank=True, max_length=200) # max length on prod: 25 email_contact = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 email_support = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 social_twitter = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_facebook = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_instagram = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 footer_links = models.TextField(default='', blank=True) facebook_app_id = models.BigIntegerField(blank=True, null=True) example = models.CharField(null=True, blank=True, max_length=20) # max length on prod: 5 licenses_acceptable = models.ManyToManyField(NodeLicense, blank=True, related_name='licenses_acceptable') default_license = models.ForeignKey(NodeLicense, related_name='default_license', null=True, blank=True, on_delete=models.CASCADE) allow_submissions = models.BooleanField(default=True) allow_commenting = models.BooleanField(default=False) access_token = EncryptedTextField(null=True, blank=True) brand = models.ForeignKey('Brand', related_name='providers', null=True, blank=True, on_delete=models.SET_NULL) branded_discovery_page = models.BooleanField(default=True) advertises_on_discovery = models.BooleanField(default=True) has_landing_page = models.BooleanField(default=False) share_publish_type = models.CharField( choices=PUSH_SHARE_TYPE_CHOICES, help_text=PUSH_SHARE_TYPE_HELP, default='Thesis', max_length=32 ) share_source = models.CharField(blank=True, default='', max_length=200) share_title = models.TextField(default='', blank=True) access_token = EncryptedTextField(null=True, blank=True) def __repr__(self): return ('(name={self.name!r}, default_license={self.default_license!r}, ' 'allow_submissions={self.allow_submissions!r}) with id {self.id!r}').format(self=self) def __str__(self): return '[{}] {} - {}'.format(self.readable_type, self.name, self.id) @property def all_subjects(self): if self.subjects.exists(): return self.subjects.all() return Subject.objects.filter( provider___id='osf', provider__type='osf.preprintprovider', ) @property def has_highlighted_subjects(self): return self.subjects.filter(highlighted=True).exists() @property def highlighted_subjects(self): if self.has_highlighted_subjects: return self.subjects.filter(highlighted=True).order_by('text')[:10] else: return sorted(self.top_level_subjects, key=lambda s: s.text)[:10] @property def top_level_subjects(self): if self.subjects.exists(): return optimize_subject_query(self.subjects.filter(parent__isnull=True)) return optimize_subject_query(Subject.objects.filter( parent__isnull=True, provider___id='osf', provider__type='osf.preprintprovider', )) @property def readable_type(self): raise NotImplementedError def get_asset_url(self, name): """ Helper that returns an associated ProviderAssetFile's url, or None :param str name: Name to perform lookup by :returns str|None: url of file """ try: return self.asset_files.get(name=name).file.url except ProviderAssetFile.DoesNotExist: return None def setup_share_source(self, provider_home_page): if self.access_token: raise ValidationError('Cannot update access_token because one or the other already exists') if not settings.SHARE_ENABLED or not settings.SHARE_URL: raise ValidationError('SHARE_ENABLED is set to false') if not self.get_asset_url('square_color_no_transparent'): raise ValidationError('Unable to find "square_color_no_transparent" icon for provider') if settings.SHARE_PROVIDER_PREPEND: share_provider_name = f'{settings.SHARE_PROVIDER_PREPEND}_{self.name}' else: share_provider_name = self.name resp = requests.post( f'{settings.SHARE_URL}api/v2/sources/', json={ 'data': { 'type': 'Source', 'attributes': { 'homePage': provider_home_page, 'longTitle': share_provider_name, 'iconUrl': self.get_asset_url('square_color_no_transparent') } } }, headers={ 'Authorization': f'Bearer {settings.SHARE_API_TOKEN}', 'Content-Type': 'application/vnd.api+json' } ) resp.raise_for_status() resp_json = resp.json() self.share_source = resp_json['data']['attributes']['longTitle'] for data in resp_json['included']: if data['type'] == 'ShareUser': self.access_token = data['attributes']['token'] self.save()
class PreprintProvider(ObjectIDMixin, ReviewProviderMixin, DirtyFieldsMixin, BaseModel): PUSH_SHARE_TYPE_CHOICES = ( ('Preprint', 'Preprint'), ('Thesis', 'Thesis'), ) PUSH_SHARE_TYPE_HELP = 'This SHARE type will be used when pushing publications to SHARE' REVIEWABLE_RELATION_NAME = 'preprint_services' name = models.CharField(null=False, max_length=128) # max length on prod: 22 description = models.TextField(default='', blank=True) domain = models.URLField(blank=True, default='', max_length=200) domain_redirect_enabled = models.BooleanField(default=False) external_url = models.URLField(null=True, blank=True, max_length=200) # max length on prod: 25 email_contact = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 email_support = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 23 example = models.CharField(null=True, blank=True, max_length=20) # max length on prod: 5 access_token = EncryptedTextField(null=True, blank=True) advisory_board = models.TextField(default='', blank=True) social_twitter = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_facebook = models.CharField(null=True, blank=True, max_length=200) # max length on prod: 8 social_instagram = models.CharField( null=True, blank=True, max_length=200) # max length on prod: 8 footer_links = models.TextField(default='', blank=True) share_publish_type = models.CharField(choices=PUSH_SHARE_TYPE_CHOICES, default='Preprint', help_text=PUSH_SHARE_TYPE_HELP, max_length=32) share_source = models.CharField(blank=True, max_length=200) share_title = models.TextField(default='', blank=True) allow_submissions = models.BooleanField(default=True) additional_providers = fields.ArrayField(models.CharField(max_length=200), default=list, blank=True) facebook_app_id = models.BigIntegerField(blank=True, null=True) PREPRINT_WORD_CHOICES = (('preprint', 'Preprint'), ('paper', 'Paper'), ('thesis', 'Thesis'), ('none', 'None')) preprint_word = models.CharField(max_length=10, choices=PREPRINT_WORD_CHOICES, default='preprint') subjects_acceptable = DateTimeAwareJSONField(blank=True, default=list) licenses_acceptable = models.ManyToManyField( NodeLicense, blank=True, related_name='licenses_acceptable') default_license = models.ForeignKey(NodeLicense, related_name='default_license', null=True, blank=True, on_delete=models.CASCADE) class Meta: permissions = tuple(PERMISSIONS.items()) + ( # custom permissions for use in the OSF Admin App ('view_preprintprovider', 'Can view preprint provider details'), ) def __unicode__(self): return '{} with id {}'.format(self.name, self.id) @property def has_highlighted_subjects(self): return self.subjects.filter(highlighted=True).exists() @property def highlighted_subjects(self): if self.has_highlighted_subjects: return self.subjects.filter(highlighted=True).order_by('text')[:10] else: return sorted(self.top_level_subjects, key=lambda s: s.text)[:10] @property def top_level_subjects(self): if self.subjects.exists(): return optimize_subject_query( self.subjects.filter(parent__isnull=True)) else: # TODO: Delet this when all PreprintProviders have a mapping if len(self.subjects_acceptable) == 0: return optimize_subject_query( Subject.objects.filter(parent__isnull=True, provider___id='osf')) tops = set([sub[0][0] for sub in self.subjects_acceptable]) return [Subject.load(sub) for sub in tops] @property def all_subjects(self): if self.subjects.exists(): return self.subjects.all() else: # TODO: Delet this when all PreprintProviders have a mapping return rules_to_subjects(self.subjects_acceptable) @property def landing_url(self): return self.domain if self.domain else '{}preprints/{}'.format( settings.DOMAIN, self.name.lower()) def get_absolute_url(self): return '{}preprint_providers/{}'.format(self.absolute_api_v2_url, self._id) @property def absolute_api_v2_url(self): path = '/preprint_providers/{}/'.format(self._id) return api_v2_url(path) def save(self, *args, **kwargs): dirty_fields = self.get_dirty_fields() old_id = dirty_fields.get('_id', None) if old_id: for permission_type in GROUPS.keys(): Group.objects.filter(name=GROUP_FORMAT.format( provider_id=old_id, group=permission_type)).update( name=GROUP_FORMAT.format(provider_id=self._id, group=permission_type)) return super(PreprintProvider, self).save(*args, **kwargs)