Exemplo n.º 1
0
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',
        )]
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
 def field(self):
     return EncryptedTextField(null=True, blank=True)
Exemplo n.º 5
0
class RdmFcmDevice(BaseModel):
    user = models.ForeignKey('OSFUser', null=True)
    device_token = EncryptedTextField(blank=True, null=True)
    date_created = NonNaiveDateTimeField(auto_now_add=True)
Exemplo n.º 6
0
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)
Exemplo n.º 7
0
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
Exemplo n.º 8
0
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()
Exemplo n.º 9
0
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()
Exemplo n.º 10
0
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)