Esempio n. 1
0
class StyleguideData(models.Model):
    """
    Data we store for the styleguide

    Each user gets one of these and we use it to store data needed to test out
    the styleguide.
    """
    user = models.OneToOneField(User)
    thumbnail = S3EnabledImageField(blank=True,
                                    upload_to='styleguide/thumbnail/',
                                    thumb_sizes=((169, 100), ))
Esempio n. 2
0
class Video(models.Model):
    """Central object in the system"""
    video_id = models.CharField(max_length=255, unique=True)
    title = models.CharField(max_length=2048, blank=True)
    description = models.TextField(blank=True)
    duration = models.PositiveIntegerField(null=True, blank=True)
    allow_community_edits = models.BooleanField()
    allow_video_urls_edit = models.BooleanField(default=True)
    writelock_time = models.DateTimeField(null=True, editable=False)
    writelock_session_key = models.CharField(max_length=255, editable=False)
    writelock_owner = models.ForeignKey(User,
                                        null=True,
                                        editable=False,
                                        related_name="writelock_owners")
    is_subtitled = models.BooleanField(default=False)
    was_subtitled = models.BooleanField(default=False, db_index=True)
    thumbnail = models.CharField(max_length=500, blank=True)
    s3_thumbnail = S3EnabledImageField(blank=True,
                                       upload_to='video/thumbnail/')
    edited = models.DateTimeField(null=True, editable=False)
    created = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, null=True, blank=True)
    followers = models.ManyToManyField(User,
                                       blank=True,
                                       related_name='followed_videos')
    complete_date = models.DateTimeField(null=True, blank=True, editable=False)

    subtitles_fetched_count = models.IntegerField(default=0, db_index=True)
    widget_views_count = models.IntegerField(default=0, db_index=True)
    view_count = models.PositiveIntegerField(default=0, db_index=True)

    subtitles_fetched_counter = RedisSimpleField('video_id', changed_video_set)
    widget_views_counter = RedisSimpleField('video_id', changed_video_set)
    view_counter = RedisSimpleField('video_id', changed_video_set)

    # Denormalizing the subtitles(had_version) count, in order to get faster joins
    # updated from update_languages_count()
    languages_count = models.PositiveIntegerField(default=0, db_index=True)

    def __unicode__(self):
        title = self.title_display()
        if len(title) > 70:
            title = title[:70] + '...'
        return title

    def title_display(self):
        if self.title:
            return self.title

        try:
            url = self.videourl_set.all()[:1].get().url
            if not url:
                return 'No title'
        except models.ObjectDoesNotExist:
            return 'No title'

        url = url.strip('/')

        if url.startswith('http://'):
            url = url[7:]

        parts = url.split('/')
        if len(parts) > 1:
            title = '%s/.../%s' % (parts[0], parts[-1])
        else:
            title = url

        if title > 35:
            title = title[:35] + '...'

        return title

    def update_view_counter(self):
        self.view_counter.incr()
        video_view_counter.incr()

    def update_subtitles_fetched(self, lang=None):
        self.subtitles_fetched_counter.incr()
        #Video.objects.filter(pk=self.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1)
        update_subtitles_fetch_counter(self, lang)
        if lang:
            lang.subtitles_fetched_counter.incr()
            #SubtitleLanguage.objects.filter(pk=sub_lang.pk).update(subtitles_fetched_count=models.F('subtitles_fetched_count')+1)

    def get_thumbnail(self):
        if self.s3_thumbnail:
            return self.s3_thumbnail.thumb_url(100, 100)

        if self.thumbnail:
            return self.thumbnail

        return ''

    def get_small_thumbnail(self):
        if self.s3_thumbnail:
            return self.s3_thumbnail.thumb_url(50, 50)

        return ''

    @models.permalink
    def video_link(self):
        return ('videos:history', [self.video_id])

    def thumbnail_link(self):
        if not self.thumbnail:
            return ''

        if self.thumbnail.startswith('http://'):
            return self.thumbnail

        return settings.MEDIA_URL + self.thumbnail

    def is_html5(self):
        try:
            return self.videourl_set.filter(original=True)[:1].get().is_html5()
        except models.ObjectDoesNotExist:
            return False

    def search_page_url(self):
        return self.get_absolute_url()

    def title_for_url(self):
        return self.title.replace('/', '-').replace('#', '').replace('?', '')

    @models.permalink
    def get_absolute_url(self, locale=None):
        kwargs = {}
        if locale:
            kwargs['locale'] = locale
        title = self.title_for_url()
        if title:
            return ('videos:video_with_title', [self.video_id, title], kwargs)
        return ('videos:video', [self.video_id], kwargs)

    def get_video_url(self):
        try:
            return self.videourl_set.filter(
                primary=True).all()[:1].get().effective_url
        except models.ObjectDoesNotExist:
            pass

    @classmethod
    def get_or_create_for_url(cls, video_url=None, vt=None, user=None):
        vt = vt or video_type_registrar.video_type_for_url(video_url)
        if not vt:
            return None, False

        try:
            video_url_obj = VideoUrl.objects.get(url=vt.convert_to_video_url())
            return video_url_obj.video, False
        except models.ObjectDoesNotExist:
            pass

        try:
            video_url_obj = VideoUrl.objects.get(type=vt.abbreviation,
                                                 **vt.create_kwars())
            if user:
                Action.create_video_handler(video_url_obj.video, user)
            return video_url_obj.video, False
        except models.ObjectDoesNotExist:
            obj = Video()
            obj = vt.set_values(obj)
            if obj.title:
                obj.slug = slugify(obj.title)
            obj.user = user
            obj.save()

            user and obj.followers.add(user)

            Action.create_video_handler(obj, user)

            SubtitleLanguage(video=obj, is_original=True,
                             is_forked=True).save()
            #Save video url
            video_url_obj = VideoUrl()
            if vt.video_id:
                video_url_obj.videoid = vt.video_id
            video_url_obj.url = vt.convert_to_video_url()
            video_url_obj.type = vt.abbreviation
            video_url_obj.original = True
            video_url_obj.primary = True
            video_url_obj.added_by = user
            video_url_obj.video = obj
            video_url_obj.save()

            return obj, True

    @property
    def language(self):
        ol = self._original_subtitle_language()

        if ol and ol.language:
            return ol.language

    @property
    def filename(self):
        from django.utils.text import get_valid_filename

        return get_valid_filename(self.__unicode__())

    def lang_filename(self, language):
        name = self.filename
        lang = language.language or u'original'
        return u'%s.%s' % (name, lang)

    @property
    def subtitle_state(self):
        """Subtitling state for this video 
        """
        return NO_SUBTITLES if self.latest_version() \
            is None else SUBTITLES_FINISHED

    def _original_subtitle_language(self):
        if not hasattr(self, '_original_subtitle'):
            try:
                original = self.subtitlelanguage_set.filter(
                    is_original=True)[:1].get()
            except models.ObjectDoesNotExist:
                original = None

            setattr(self, '_original_subtitle', original)

        return getattr(self, '_original_subtitle')

    def has_original_language(self):
        original_language = self._original_subtitle_language()
        if original_language:
            return original_language.language != ''

    def subtitle_language(self, language_code=None):
        try:
            if language_code is None:
                return self._original_subtitle_language()
            else:
                return self.subtitlelanguage_set.filter(
                    language=language_code).order_by(
                        '-subtitle_count')[:1].get()
        except models.ObjectDoesNotExist:
            return None

    def subtitle_languages(self, language_code):
        return self.subtitlelanguage_set.filter(language=language_code)

    def version(self, version_no=None, language=None):
        if language is None:
            language = self.subtitle_language()
        return None if language is None else language.version(version_no)

    def latest_version(self, language_code=None):
        language = self.subtitle_language(language_code)
        return None if language is None else language.latest_version()

    def subtitles(self, version_no=None, language_code=None):
        version = self.version(version_no, language_code)
        if version:
            return version.subtitles()
        else:
            return Subtitle.objects.none()

    def update_languages_count(self):
        self.languages_count = self.subtitlelanguage_set.filter(
            had_version=True).count()
        self.save()

    def latest_subtitles(self, language_code=None):
        version = self.latest_version(language_code)
        return [] if version is None else version.subtitles()

    def translation_language_codes(self):
        """All iso language codes with finished translations."""
        return set([
            sl.language for sl in self.subtitlelanguage_set.filter(
                is_complete=True).filter(is_original=False)
        ])

    @property
    def writelock_owner_name(self):
        """The user who currently has a subtitling writelock on this video."""
        if self.writelock_owner == None:
            return "anonymous"
        else:
            return self.writelock_owner.__unicode__()

    @property
    def is_writelocked(self):
        """Is this video writelocked for subtitling?"""
        if self.writelock_time == None:
            return False
        delta = datetime.now() - self.writelock_time
        seconds = delta.days * 24 * 60 * 60 + delta.seconds
        return seconds < WRITELOCK_EXPIRATION

    def can_writelock(self, request):
        """Can I place a writelock on this video for subtitling?"""
        return self.writelock_session_key == \
            request.browser_id or \
            not self.is_writelocked

    def writelock(self, request):
        """Writelock this video for subtitling."""
        self._make_writelock(request.user, request.browser_id)

    def _make_writelock(self, user, key):
        if user.is_authenticated():
            self.writelock_owner = user
        else:
            self.writelock_owner = None
        self.writelock_session_key = key
        self.writelock_time = datetime.now()

    def release_writelock(self):
        """Writelock this video for subtitling."""
        self.writelock_owner = None
        self.writelock_session_key = ''
        self.writelock_time = None

    def notification_list(self, exclude=None):
        qs = self.followers.exclude(changes_notification=False).exclude(
            is_active=False)
        if exclude:
            if not isinstance(exclude, (list, tuple)):
                exclude = [exclude]
            qs = qs.exclude(
                pk__in=[u.pk for u in exclude if u and u.is_authenticated()])
        return qs

    def notification_list_all(self, exclude=None):
        users = []
        for language in self.subtitlelanguage_set.all():
            for u in language.notification_list(exclude):
                if not u in users:
                    users.append(u)
        for user in self.notification_list(exclude):
            if not user in users:
                users.append(user)
        return users

    def update_complete_state(self):
        language = self.subtitle_language()
        if not language.has_version:
            self.is_subtitled = False
        else:
            self.is_subtitled = True
            self.was_subtitled = True

    def subtitle_language_dict(self):
        langs = {}
        for sl in self.subtitlelanguage_set.all():
            if not sl.language:
                continue
            if sl.language in langs:
                langs[sl.language].append(sl)
            else:
                langs[sl.language] = [sl]
        return langs
Esempio n. 3
0
class CustomUser(BaseUser, secureid.SecureIDMixin):
    AUTOPLAY_ON_BROWSER = 1
    AUTOPLAY_ON_LANGUAGES = 2
    DONT_AUTOPLAY = 3
    AUTOPLAY_CHOICES = (
        (AUTOPLAY_ON_BROWSER,
         'Autoplay subtitles based on browser preferred languages'),
        (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'),
        (DONT_AUTOPLAY, 'Don\'t autoplay subtitles'))
    PLAYBACK_MODE_MAGIC = 1
    PLAYBACK_MODE_STANDARD = 2
    PLAYBACK_MODE_BEGINNER = 3
    PLAYBACK_MODE_CHOICES = ((PLAYBACK_MODE_MAGIC, 'Magical auto-pause'),
                             (PLAYBACK_MODE_STANDARD, 'No automatic pausing'),
                             (PLAYBACK_MODE_BEGINNER,
                              'Play for 4 seconds, then pause'))
    homepage = models.URLField(blank=True)
    preferred_language = models.CharField(max_length=16,
                                          choices=ALL_LANGUAGES,
                                          blank=True)
    picture = S3EnabledImageField(blank=True,
                                  upload_to='pictures/',
                                  thumb_sizes=[(240, 240), (110, 110),
                                               (100, 100), (50, 50), (30, 30)])
    valid_email = models.BooleanField(default=False)

    # if true, items that end on the user activity stream will also be
    # sent as email
    notify_by_email = models.BooleanField(default=True)
    # if true, items that end on the user activity stream will also be
    # sent as a message
    notify_by_message = models.BooleanField(default=True)
    allow_3rd_party_login = models.BooleanField(default=False)
    biography = models.TextField('Bio', blank=True)
    autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES,
                                               default=AUTOPLAY_ON_BROWSER)
    award_points = models.IntegerField(default=0)
    last_ip = models.GenericIPAddressField(blank=True, null=True)
    # videos witch are related to user. this is for quicker queries
    videos = models.ManyToManyField('videos.Video', blank=True)
    # for some login backends we end up with a full name but not
    # a first name, last name pair.
    full_name = models.CharField(max_length=63, blank=True, default='')
    partner = models.ForeignKey('teams.Partner', blank=True, null=True)
    is_partner = models.BooleanField(default=False)
    pay_rate_code = models.CharField(max_length=3, blank=True, default='')
    can_send_messages = models.BooleanField(default=True)
    show_tutorial = models.BooleanField(default=True)
    # Whenever a user hides the "You have XX new messages" alert, we record
    # the id of the last message.  We don't show the alert again until the
    # user has a message newer than that message.
    last_hidden_message_id = models.PositiveIntegerField(blank=True, default=0)
    playback_mode = models.IntegerField(choices=PLAYBACK_MODE_CHOICES,
                                        default=PLAYBACK_MODE_STANDARD)
    created_by = models.ForeignKey('self',
                                   null=True,
                                   blank=True,
                                   related_name='created_users')
    # For storing usernames of deactivated accounts, deleted accounts should not store the old username
    username_old = models.CharField(max_length=30,
                                    blank=True,
                                    null=True,
                                    default='')

    SECURE_ID_KEY = 'User'

    objects = CustomUserManager()

    cache = ModelCacheManager(default_cache_pattern='user')

    # Fields that constitute a user's profile, things like names, bios, etc.
    # When these change we emit the user_profile_changed signal.
    PROFILE_FIELDS = [
        'first_name',
        'last_name',
        'full_name',
        'biography',
        'picture',
        'homepage',
        'email',
    ]

    class Meta:
        db_table = 'auth_customuser'
        verbose_name = 'User'

    def __init__(self, *args, **kwargs):
        super(CustomUser, self).__init__(*args, **kwargs)
        self.start_tracking_profile_fields()

    def __unicode__(self):
        if self.is_amara_anonymous:
            return settings.ANONYMOUS_FULL_NAME
        elif not self.is_active:
            return ugettext('Retired user')
        elif self.first_name or self.last_name:
            return self.get_full_name()
        elif self.full_name:
            return self.full_name
        else:
            return self.username

    @staticmethod
    def generate_random_username():
        username = str(uuid.uuid4())[0:30]
        try:
            CustomUser.objects.get(username=username)
            return generate_random_username()
        except CustomUser.DoesNotExist:
            return username

    @property
    def display_username(self):
        if self.is_active:
            return self.username
        else:
            return ugettext('Retired user')

    @property
    def username_with_fullname(self):
        if self.is_active:
            return self.username + ("" if unicode(self) == self.username else
                                    " ({})".format(unicode(self)))
        else:
            return ugettext('Retired user')

    # Returns a dictionary in the select2 data format
    def get_select2_format(self):
        return {'id': self.username, 'text': self.username_with_fullname}

    def sent_message(self):
        """
        Should be called each time a user sends a message.
        This is used to control if a user is spamming.
        """
        if hasattr(settings, 'MESSAGES_SENT_WINDOW_MINUTES') and \
           hasattr(settings, 'MESSAGES_SENT_LIMIT'):
            SentMessageDate.objects.sent_message(self)
            self._check_sent_messages()

    def _check_sent_messages(self):
        if hasattr(settings, 'MESSAGES_SENT_WINDOW_MINUTES') and \
           hasattr(settings, 'MESSAGES_SENT_LIMIT'):
            if SentMessageDate.objects.check_too_many_messages(self):
                self.de_activate()

    def de_activate(self):
        if not self.is_superuser:
            self.is_active = False
            self.save()
            import tasks
            tasks.notify_blocked_user.delay(self)

    def deactivate_account(self):
        with transaction.atomic():
            self.unlink_external()
            self.team_members.all().delete()
            self.username_old = self.username
            self.username = CustomUser.generate_random_username()
            self.is_active = False
            self.save()
            signals.user_account_deactivated.send(sender=self)

    def delete_account_data(self):
        # Alternate implementation is to blank all the fields except for some fields
        # indicated in skip_fields
        #
        # for field in self._meta.fields:
        #     if field.name in skip_fields:
        #         continue
        #     if field.default != NOT_PROVIDED:
        #         setattr(self, field.name, field.default)
        #     else:
        #         setattr(self, field.name, None)

        self.username = CustomUser.generate_random_username()
        self.username_old = None
        self.first_name = ""
        self.last_name = ""
        self.picture = None
        self.email = ""
        self.homepage = ""
        self.biography = ""
        self.full_name = ""
        self.save()

    # Deletes videos this user has uploaded and no one else has added subtitles to
    # Also deletes uploaded videos without subtitles
    # Does not delete team videos
    def delete_self_subtitled_videos(self):
        for video in self.videos.all():
            if (video.is_solo_subtitled_by_uploader()
                    and not video.is_team_video()):
                video.delete()

    def has_fullname_set(self):
        return any([self.first_name, self.last_name, self.full_name])

    def display_name(self):
        if self.has_fullname_set():
            return u'{} ({})'.format(unicode(self), self.username)
        else:
            return unicode(self.username)

    def save(self, *args, **kwargs):
        send_confirmation = False

        if not self.email:
            self.valid_email = False
        elif self.pk:
            try:
                before_save = self.__class__._default_manager.get(pk=self.pk)
                send_confirmation = before_save.email != self.email
            except models.ObjectDoesNotExist:
                send_confirmation = True
        elif self.email:
            send_confirmation = True

        if send_confirmation:
            self.valid_email = False

        send_email_confirmation = kwargs.pop('send_email_confirmation', True)
        if self.pk:
            self.check_profile_changed()
        super(CustomUser, self).save(*args, **kwargs)
        self.start_tracking_profile_fields()

        if send_confirmation and send_email_confirmation:
            EmailConfirmation.objects.send_confirmation(self)

    def start_tracking_profile_fields(self):
        self._initial_profile_data = self.calc_profile_data()

    def calc_profile_data(self):
        return {
            name: getattr(self, name)
            for name in CustomUser.PROFILE_FIELDS
        }

    def check_profile_changed(self):
        if self.calc_profile_data() != self._initial_profile_data:
            signals.user_profile_changed.send(self)

    def clean(self):
        if '$' in self.username:
            raise ValidationError("usernames can't contain the '$' character")

    def set_last_hidden_message_id(self, request, message_id):
        if message_id != self.last_hidden_message_id:
            self.last_hidden_message_id = message_id
            self.save()
            # cycle the session key to bust the varnish cache
            request.session.cycle_key()

    def new_messages_count(self):
        """
        Number of messages we should show in the "You have XX new messages
        alert"

        These are messages that:
          - Are unread
          - Have come in after the last time the user hide that message,
            or viewed their inbox

        """
        from messages.models import Message
        qs = (Message.objects.for_user(self).filter(
            read=False, id__gt=self.last_hidden_message_id))
        return qs.count()

    def last_message_id(self):
        """
        The id of the last message for the user.

        Returns: message id, or 0 if there are no messages
        """
        from messages.models import Message
        qs = Message.objects.for_user(self).order_by('-id')[:1]
        if qs:
            return qs[0].id
        else:
            return 0

    def tutorial_was_shown(self):
        CustomUser.objects.filter(pk=self.id).update(show_tutorial=False)

    def set_playback_mode(self, playback_mode):
        CustomUser.objects.filter(pk=self.id).update(
            playback_mode=playback_mode)

    @classmethod
    def displayable_users(self, ids):
        return self.objects.filter(pk__in=ids).values_list(
            'pk', 'first_name', 'last_name', 'username')

    @classmethod
    def video_followers_change_handler(cls, sender, instance, action, reverse,
                                       model, pk_set, **kwargs):
        from videos.models import SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for video_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video__pk=video_pk,
                    customuser=instance,
                    defaults={'video_id': video_pk})
        elif reverse and action == 'post_remove':
            #instance is User
            for video_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers=instance, video__pk=video_pk).exists():
                    instance.videos.remove(video_pk)
        elif not reverse and action == 'post_add':
            #instance is Video
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is Video
            for user_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers__pk=user_pk, video=instance).exists():
                    instance.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is Video
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance).delete()

    @classmethod
    def sl_followers_change_handler(cls, sender, instance, action, reverse,
                                    model, pk_set, **kwargs):
        from videos.models import Video, SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for sl_pk in pk_set:
                sl = SubtitleLanguage.objects.get(pk=sl_pk)
                cls.videos.through.objects.get_or_create(video=sl.video,
                                                         customuser=instance)
        elif reverse and action == 'post_remove':
            #instance is User
            for sl_pk in pk_set:
                if not Video.objects.filter(
                        followers=instance,
                        subtitlelanguage__pk=sl_pk).exists():
                    sl = SubtitleLanguage.objects.get(pk=sl_pk)
                    instance.videos.remove(sl.video)
        elif not reverse and action == 'post_add':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance.video,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                if not Video.objects.filter(
                        followers__pk=user_pk,
                        subtitlelanguage=instance).exists():
                    instance.video.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is SubtitleLanguage
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance.video).delete()

    def get_languages(self):
        """Get a list of language codes that the user speaks."""
        return self.cache.get_or_calc("languages", self.calc_languages)

    def calc_languages(self):
        return list(
            self.userlanguage_set.order_by("priority").values_list('language',
                                                                   flat=True))

    def set_languages(self, languages):
        with transaction.atomic():
            # need to delete all the set languages since there is some funky stuff
            # happening if a user sets the same languages but with different priorities
            self.userlanguage_set.all().delete()
            self.userlanguage_set.set([
                UserLanguage.objects.create(user=self,
                                            language=l["language"],
                                            priority=l["priority"])
                for l in languages
            ])
        self.cache.invalidate()
        signals.user_profile_changed.send(self)

    def get_language_names(self):
        """Get a list of language names that the user speaks."""
        return [
            translation.get_language_label(lc) for lc in self.get_languages()
        ]

    def get_language_codes_and_names(self):
        """Get a list of language codes/names that the user speaks."""
        return [(lc, translation.get_language_label(lc))
                for lc in self.get_languages()]

    def speaks_language(self, language_code):
        return language_code in [l.language for l in self.get_languages()]

    def is_team_manager(self):
        cached_value = self.cache.get('is-manager')
        if cached_value is not None:
            return cached_value
        is_manager = self.managed_teams().exists()
        self.cache.set('is-manager', is_manager)
        return is_manager

    def managed_teams(self, include_manager=True):
        from teams.models import TeamMember
        possible_roles = [TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN]
        if include_manager:
            possible_roles.append(TeamMember.ROLE_MANAGER)
        return self.teams.filter(members__role__in=possible_roles)

    def messageable_teams(self):
        from teams.models import Team
        from teams.permissions import can_message_all_members

        teams = self.teams.all()
        messageable_team_ids = [
            t.id for t in teams if can_message_all_members(t, self)
        ]

        partners = self.managed_partners.all()
        teams = [list(p.teams.all()) for p in partners]
        partner_teams_ids = [team.id for qs in teams for team in qs]

        messageable_team_ids = messageable_team_ids + partner_teams_ids
        return Team.objects.filter(id__in=messageable_team_ids)

    def open_tasks(self):
        from teams.models import Task
        return Task.objects.incomplete().filter(assignee=self)

    def _get_gravatar(self, size, default='mm'):
        url = "https://www.gravatar.com/avatar/" + hashlib.md5(
            self.email.lower().encode('utf-8')).hexdigest() + "?"
        url += urllib.urlencode({'d': default, 's': str(size)})
        return url

    # old UI avatars
    def _get_avatar_by_size(self, size):
        if self.picture:
            return self.picture.thumb_url(size, size)
        else:
            return self._get_gravatar(size)

    def avatar(self):
        return self._get_avatar_by_size(100)

    def small_avatar(self):
        return self._get_avatar_by_size(50)

    def large_avatar(self):
        return self._get_avatar_by_size(240)

    # future UI avatar
    def _get_avatar(self, size):
        if self.picture:
            return self.picture.thumb_url(size, size)
        else:
            return self._get_gravatar(
                size, default=DEFAULT_AVATAR_URL.format(size=size))

    def avatar_tag(self):
        avatar = self._get_avatar(30)
        return mark_safe(
            '<span class="avatar"><img src="{}"></span>'.format(avatar))

    def avatar_tag_alert(self):
        avatar = self._get_avatar(30)
        return mark_safe(
            '<span class="avatar avatar-alert"><img src="{}"></span>'.format(
                avatar))

    def avatar_tag_medium(self):
        avatar = self._get_avatar(50)
        return mark_safe(
            '<span class="avatar avatar-md"><img src="{}"></span>'.format(
                avatar))

    def avatar_tag_large(self):
        avatar = self._get_avatar(100)
        return mark_safe(
            '<span class="avatar avatar-lg"><img src="{}"></span>'.format(
                avatar))

    def avatar_tag_extra_large(self):
        avatar = self._get_avatar(110)
        return mark_safe(
            '<span class="avatar avatar-xl"><img src="{}"></span>'.format(
                avatar))

    def get_absolute_url(self):
        return reverse('profiles:profile', args=(self.username, ))

    def send_message_url(self, absolute_url=False):
        url = '{}?user={}'.format(reverse('messages:new'),
                                  urlquote(self.username))
        if absolute_url:
            url = "{}://{}{}".format(settings.DEFAULT_PROTOCOL,
                                     settings.HOSTNAME, url)
        return url

    @property
    def language(self):
        return self.get_preferred_language_display()

    def guess_best_lang(self, request=None):

        if self.preferred_language:
            return self.preferred_language

        user_languages = self.get_languages()
        if user_languages:
            return user_languages[0]

        if request:
            languages = translation.get_user_languages_from_request(request)
            if languages:
                return languages[0]

        return 'en'

    def guess_is_rtl(self, request=None):
        return translation.is_rtl(self.guess_best_lang(request))

    @models.permalink
    def profile_url(self):
        return ('profiles:profile', [self.pk])

    def hash_for_video(self, video_id):
        return hashlib.sha224(settings.SECRET_KEY + str(self.pk) +
                              video_id).hexdigest()

    @classmethod
    def get_amara_anonymous(cls):
        return get_amara_anonymous_user()

    @property
    def is_amara_anonymous(self):
        return self.pk == settings.ANONYMOUS_USER_ID

    @property
    def is_external(self):
        """
        Checks whether accout is external
        It can me an OpeenId link or a token stored as
        a ThirdPartyAccount
        """
        try:
            l = self.openid_connect_link
            return True
        except:
            from thirdpartyaccounts import get_thirdpartyaccount_types
            for thirdpartyaccount_type in get_thirdpartyaccount_types():
                m = apps.get_model(thirdpartyaccount_type[0],
                                   thirdpartyaccount_type[1])
                if (m is not None) and (len(m.objects.for_user(self)) > 0):
                    return True
        return False

    def has_valid_password(self):
        # remove this post-1.9 when setting is used
        validator = PasswordStrengthValidator()
        try:
            validator.validate(self.password)
        except ValidationError:
            return False
        return len(self.password) > 0 and self.has_usable_password()

    '''
    Unlinks external authentication accounts (OAuth, Google, Facebook, etc. logins)
    '''

    def unlink_external(self):
        from thirdpartyaccounts import get_thirdpartyaccount_types
        for thirdpartyaccount_type in get_thirdpartyaccount_types():
            m = apps.get_model(thirdpartyaccount_type[0],
                               thirdpartyaccount_type[1])
            if m is not None:
                m.objects.for_user(self).delete()
        try:
            self.openid_connect_link.delete()
        except:
            pass

    def check_api_key(self, key):
        try:
            return self.api_key.key == key
        except AmaraApiKey.DoesNotExist:
            return False

    def get_api_key(self):
        return AmaraApiKey.objects.get_or_create(user=self)[0].key

    def ensure_api_key_created(self):
        AmaraApiKey.objects.get_or_create(user=self)
Esempio n. 4
0
class Team(models.Model):
    APPLICATION = 1
    INVITATION_BY_MANAGER = 2
    INVITATION_BY_ALL = 3
    OPEN = 4
    MEMBERSHIP_POLICY_CHOICES = (
        (APPLICATION, _(u'Application')),
        (INVITATION_BY_MANAGER, _(u'Invitation by manager')),
        (INVITATION_BY_ALL, _(u'Invitation by any member')),
        (OPEN, _(u'Open')),
    )
    MEMBER_REMOVE = 1
    MANAGER_REMOVE = 2
    MEMBER_ADD = 3
    VIDEO_POLICY_CHOICES = (
        (MEMBER_REMOVE, _(u'Members can add and remove video')
         ),  #any member can add/delete video
        (MANAGER_REMOVE, _(u'Managers can add and remove video')
         ),  #only managers can add/remove video
        (MEMBER_ADD, _(u'Members can only add videos')
         )  #members can only add video
    )

    name = models.CharField(_(u'name'), max_length=250, unique=True)
    slug = models.SlugField(_(u'slug'), unique=True)
    description = models.TextField(
        _(u'description'),
        blank=True,
        help_text=_('All urls will be converted to links.'))

    logo = S3EnabledImageField(verbose_name=_(u'logo'),
                               blank=True,
                               upload_to='teams/logo/')
    membership_policy = models.IntegerField(_(u'membership policy'),
                                            choices=MEMBERSHIP_POLICY_CHOICES,
                                            default=OPEN)
    video_policy = models.IntegerField(_(u'video policy'),
                                       choices=VIDEO_POLICY_CHOICES,
                                       default=MEMBER_REMOVE)
    is_visible = models.BooleanField(_(u'publicly Visible?'), default=True)
    videos = models.ManyToManyField(Video,
                                    through='TeamVideo',
                                    verbose_name=_('videos'))
    users = models.ManyToManyField(User,
                                   through='TeamMember',
                                   related_name='teams',
                                   verbose_name=_('users'))
    points = models.IntegerField(default=0, editable=False)
    applicants = models.ManyToManyField(User,
                                        through='Application',
                                        related_name='applicated_teams',
                                        verbose_name=_('applicants'))
    created = models.DateTimeField(auto_now_add=True)
    highlight = models.BooleanField(default=False)
    video = models.ForeignKey(Video,
                              null=True,
                              blank=True,
                              related_name='intro_for_teams',
                              verbose_name=_(u'Intro Video'))
    application_text = models.TextField(blank=True)
    page_content = models.TextField(
        _(u'Page content'),
        blank=True,
        help_text=_(u'You can use markdown. This will replace Description.'))
    is_moderated = models.BooleanField(default=False)
    header_html_text = models.TextField(
        blank=True,
        default='',
        help_text=_(u"HTML that appears at the top of the teams page."))
    last_notification_time = models.DateTimeField(
        editable=False, default=datetime.datetime.now)

    objects = TeamManager()

    class Meta:
        ordering = ['-name']
        verbose_name = _(u'Team')
        verbose_name_plural = _(u'Teams')

    def __unicode__(self):
        return self.name

    def render_message(self, msg):
        context = {
            'team': self,
            'msg': msg,
            'author': msg.author,
            'author_page': msg.author.get_absolute_url(),
            'team_page': self.get_absolute_url()
        }
        return render_to_string('teams/_team_message.html', context)

    def is_open(self):
        return self.membership_policy == self.OPEN

    def is_by_application(self):
        return self.membership_policy == self.APPLICATION

    @classmethod
    def get(cls, slug, user=None, raise404=True):
        if user:
            qs = cls.objects.for_user(user)
        else:
            qs = cls.objects.filter(is_visible=True)
        try:
            return qs.get(slug=slug)
        except cls.DoesNotExist:
            try:
                return qs.get(pk=int(slug))
            except (cls.DoesNotExist, ValueError):
                pass

        if raise404:
            raise Http404

    def logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(100, 100)

    def small_logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(50, 50)

    @models.permalink
    def get_absolute_url(self):
        return ('teams:detail', [self.slug])

    def get_site_url(self):
        return 'http://%s%s' % (Site.objects.get_current().domain,
                                self.get_absolute_url())

    @models.permalink
    def get_edit_url(self):
        return ('teams:edit', [self.slug])

    def is_manager(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user, is_manager=True).exists()

    def is_member(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user).exists()

    def can_remove_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user):
            return True
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return False

    def can_edit_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        return self.can_add_video(user)

    def can_add_video(self, user):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return self.is_manager(user)

    def can_invite(self, user):
        if self.membership_policy == self.INVITATION_BY_MANAGER:
            return self.is_manager(user)

        return self.is_member(user)

    def can_approve_application(self, user):
        return self.is_member(user)

    @property
    def member_count(self):
        if not hasattr(self, '_member_count'):
            setattr(self, '_member_count', self.users.count())
        return self._member_count

    @property
    def videos_count(self):
        if not hasattr(self, '_videos_count'):
            setattr(self, '_videos_count', self.videos.count())
        return self._videos_count

    @property
    def applications_count(self):
        if not hasattr(self, '_applications_count'):
            setattr(self, '_applications_count', self.applications.count())
        return self._applications_count

    def _lang_pair(self, lp, suffix):
        return SQ(content="{0}_{1}_{2}".format(lp[0], lp[1], suffix))

    def _sq_expression(self, sq_list):
        if len(sq_list) == 0:
            return None
        else:
            return reduce(lambda x, y: x | y, sq_list)

    def _filter(self, sqs, sq_list):
        from haystack.query import SQ
        sq_expression = self._sq_expression(sq_list)
        return None if (sq_expression is None) else sqs.filter(sq_expression)

    def _exclude(self, sqs, sq_list):
        if sqs is None:
            return None
        sq_expression = self._sq_expression(sq_list)
        return sqs if sq_expression is None else sqs.exclude(sq_expression)

    def _base_sqs(self):
        from haystack.query import SearchQuerySet
        return SearchQuerySet().models(TeamVideo).filter(team_id=self.id)

    def get_videos_for_languages_haystack(self, languages):
        from utils.multi_query_set import MultiQuerySet

        languages.extend(
            [l[:l.find('-')] for l in languages if l.find('-') > -1])
        languages = list(set(languages))

        pairs_m, pairs_0, langs = [], [], []
        for l1 in languages:
            langs.append(SQ(content='S_{0}'.format(l1)))
            for l0 in languages:
                if l1 != l0:
                    pairs_m.append(self._lang_pair((l1, l0), "M"))
                    pairs_0.append(self._lang_pair((l1, l0), "0"))

        qs_list = []
        qs_list.append(self._filter(self._base_sqs(), pairs_m))
        qs_list.append(
            self._exclude(self._filter(self._base_sqs(), pairs_0), pairs_m))
        qs_list.append(
            self._exclude(
                self._base_sqs().filter(original_language__in=languages),
                pairs_m + pairs_0).order_by('has_lingua_franca'))
        qs_list.append(
            self._exclude(self._filter(self._base_sqs(), langs), pairs_m +
                          pairs_0).exclude(original_language__in=languages))
        qs_list.append(
            self._exclude(self._base_sqs(), langs + pairs_m +
                          pairs_0).exclude(original_language__in=languages))
        mqs = MultiQuerySet(*[qs for qs in qs_list if qs is not None])
        # this is way more efficient than making a count from all the
        # constituent querysets.
        mqs.set_count(TeamVideo.objects.filter(team=self).count())

        return qs_list, mqs

    def get_videos_for_languages(self, languages,
                                 CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS):
        from utils.multi_query_set import TeamMultyQuerySet
        languages.extend(
            [l[:l.find('-')] for l in languages if l.find('-') > -1])

        langs_pairs = []

        for l1 in languages:
            for l0 in languages:
                if not l1 == l0:
                    langs_pairs.append('%s_%s' % (l1, l0))

        qs = TeamVideoLanguagePair.objects.filter(language_pair__in=langs_pairs, team=self) \
            .select_related('team_video', 'team_video__video')
        lqs = TeamVideoLanguage.objects.filter(team=self).select_related(
            'team_video', 'team_video__video')

        qs1 = qs.filter(percent_complete__gt=0, percent_complete__lt=100)
        qs2 = qs.filter(percent_complete=0)
        qs3 = lqs.filter(is_original=True,
                         is_complete=False,
                         language__in=languages).order_by("is_lingua_franca")
        qs4 = lqs.filter(is_original=False,
                         forked=True,
                         is_complete=False,
                         language__in=languages)
        mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4)

        total_count = TeamVideo.objects.filter(team=self).count()

        additional = TeamVideoLanguagePair.objects.none()
        all_videos = TeamVideo.objects.filter(
            team=self).select_related('video')

        if total_count == 0:
            mqs = all_videos
        else:
            if total_count < CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS:
                additional = all_videos.exclude(pk__in=[x.id for x in mqs])
            else:
                additional = all_videos
            mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4, additional)

        return {
            'qs': qs,
            'lqs': lqs,
            'qs1': qs1,
            'qs2': qs2,
            'qs3': qs3,
            'qs4': qs4,
            'videos': mqs,
            'videos_count': len(mqs),
            'additional_count': additional.count(),
            'additional': additional[:50],
            'lqs': lqs,
            'qs': qs,
        }
Esempio n. 5
0
class TeamVideo(models.Model):
    team = models.ForeignKey(Team)
    video = models.ForeignKey(Video)
    title = models.CharField(max_length=2048, blank=True)
    description = models.TextField(
        blank=True,
        help_text=
        _(u'Use this space to explain why you or your team need to caption or subtitle this video. Adding a note makes volunteers more likely to help out!'
          ))
    thumbnail = S3EnabledImageField(
        upload_to='teams/video_thumbnails/',
        null=True,
        blank=True,
        help_text=_(
            u'We automatically grab thumbnails for certain sites, e.g. Youtube'
        ))
    all_languages = models.BooleanField(
        _('Need help with all languages'),
        default=False,
        help_text=_(
            'If you check this, other languages will not be displayed.'))
    added_by = models.ForeignKey(User)
    created = models.DateTimeField(auto_now_add=True)
    completed_languages = models.ManyToManyField(SubtitleLanguage, blank=True)

    class Meta:
        unique_together = (('team', 'video'), )

    def __unicode__(self):
        return self.title or self.video.__unicode__()

    def can_remove(self, user):
        return self.team.can_remove_video(user, self)

    def can_edit(self, user):
        return self.team.can_edit_video(user, self)

    def link_to_page(self):
        if self.all_languages:
            return self.video.get_absolute_url()
        return self.video.video_link()

    @models.permalink
    def get_absolute_url(self):
        return ('teams:team_video', [self.pk])

    def get_thumbnail(self):
        if self.thumbnail:
            return self.thumbnail.thumb_url(100, 100)

        if self.video.thumbnail:
            th = self.video.get_thumbnail()
            if th:
                return th

        if self.team.logo:
            return self.team.logo_thumbnail()

        return ''

    def _original_language(self):
        if not hasattr(self, 'original_language_code'):
            sub_lang = self.video.subtitle_language()
            setattr(self, 'original_language_code',
                    None if not sub_lang else sub_lang.language)
        return getattr(self, 'original_language_code')

    def _calculate_percent_complete(self, sl0, sl1):
        # maybe move this to Video model in future.
        if not sl0 or not sl0.is_dependable():
            return -1
        if not sl1:
            return 0
        if sl1.language == self._original_language():
            return -1
        if sl1.is_dependent():
            if sl1.percent_done == 0:
                return 0
            elif sl0.is_dependent():
                l_dep0 = sl0.real_standard_language()
                l_dep1 = sl1.real_standard_language()
                if l_dep0 and l_dep1 and l_dep0.id == l_dep1.id:
                    return sl1.percent_done
                else:
                    return -1
            else:
                l_dep1 = sl1.real_standard_language()
                return sl1.percent_done if \
                    l_dep1 and l_dep1.id == sl0.id else -1
        else:
            sl1_subtitle_count = 0
            latest_version = sl1.latest_version()
            if latest_version:
                sl1_subtitle_count = latest_version.subtitle_set.count()
            return 0 if sl1_subtitle_count == 0 else -1

    def _update_team_video_language_pair(self, lang0, sl0, lang1, sl1):
        percent_complete = self._calculate_percent_complete(sl0, sl1)
        if sl1 is not None:
            tvlps = TeamVideoLanguagePair.objects.filter(
                team_video=self,
                subtitle_language_0=sl0,
                subtitle_language_1=sl1)
        else:
            tvlps = TeamVideoLanguagePair.objects.filter(
                team_video=self,
                subtitle_language_0__language=lang0,
                language_1=lang1)
        tvlp = None if len(tvlps) == 0 else tvlps[0]
        if not tvlp and percent_complete != -1:
            tvlp = TeamVideoLanguagePair(team_video=self,
                                         team=self.team,
                                         video=self.video,
                                         language_0=lang0,
                                         subtitle_language_0=sl0,
                                         language_1=lang1,
                                         subtitle_language_1=sl1,
                                         language_pair='{0}_{1}'.format(
                                             lang0, lang1),
                                         percent_complete=percent_complete)
            tvlp.save()
        elif tvlp and percent_complete != -1:
            tvlp.percent_complete = percent_complete
            tvlp.save()
        elif tvlp and percent_complete == -1:
            tvlp.delete()

    def _make_lp(self, lang0, sl0, lang1, sl1):
        percent_complete = self._calculate_percent_complete(sl0, sl1)
        if percent_complete == -1:
            return None
        else:
            return "{0}_{1}_{2}".format(lang0, lang1,
                                        "M" if percent_complete > 0 else "0")

    def _update_tvlp_for_languages(self, lang0, lang1, langs):
        sl0_list = langs.get(lang0, [])
        sl1_list = langs.get(lang1, [])
        if len(sl1_list) == 0:
            sl1_list = [None]
        for sl0 in sl0_list:
            for sl1 in sl1_list:
                self._update_team_video_language_pair(lang0, sl0, lang1, sl1)

    def _add_lps_for_languages(self, lang0, lang1, langs, lps):
        sl0_list = langs.get(lang0, [])
        sl1_list = langs.get(lang1, [])
        if len(sl1_list) == 0:
            sl1_list = [None]
        for sl0 in sl0_list:
            for sl1 in sl1_list:
                lp = self._make_lp(lang0, sl0, lang1, sl1)
                if lp:
                    lps.append(lp)

    def update_team_video_language_pairs(self, lang_code_list=None):
        TeamVideoLanguagePair.objects.filter(team_video=self).delete()
        if lang_code_list is None:
            lang_code_list = [item[0] for item in settings.ALL_LANGUAGES]
        langs = self.video.subtitle_language_dict()
        for lang0, sl0_list in langs.items():
            for lang1 in lang_code_list:
                if lang0 == lang1:
                    continue
                self._update_tvlp_for_languages(lang0, lang1, langs)

    def searchable_language_pairs(self):
        lps = []
        lang_code_list = [item[0] for item in settings.ALL_LANGUAGES]
        langs = self.video.subtitle_language_dict()
        for lang0, sl0_list in langs.items():
            for lang1 in lang_code_list:
                if lang0 == lang1:
                    continue
                self._add_lps_for_languages(lang0, lang1, langs, lps)
        return lps

    def _add_searchable_language(self, language, sublang_dict, sls):
        complete_sublangs = []
        if language in sublang_dict:
            complete_sublangs = [
                sl for sl in sublang_dict[language]
                if not sl.is_dependent() and sl.is_complete
            ]
        if len(complete_sublangs) == 0:
            sls.append("S_{0}".format(language))

    def searchable_languages(self):
        sls = []
        langs = self.video.subtitle_language_dict()
        for lang in settings.ALL_LANGUAGES:
            self._add_searchable_language(lang[0], langs, sls)
        return sls
Esempio n. 6
0
class Team(models.Model):
    APPLICATION = 1
    INVITATION_BY_MANAGER = 2
    INVITATION_BY_ALL = 3
    OPEN = 4
    MEMBERSHIP_POLICY_CHOICES = (
        (APPLICATION, _(u'Application')),
        (INVITATION_BY_MANAGER, _(u'Invitation by manager')),
        (INVITATION_BY_ALL, _(u'Invitation by any member')),
        (OPEN, _(u'Open')),
    )
    MEMBER_REMOVE = 1
    MANAGER_REMOVE = 2
    MEMBER_ADD = 3
    VIDEO_POLICY_CHOICES = (
        (MEMBER_REMOVE, _(u'Members can add and remove video')
         ),  #any member can add/delete video
        (MANAGER_REMOVE, _(u'Managers can add and remove video')
         ),  #only managers can add/remove video
        (MEMBER_ADD, _(u'Members can only add videos')
         )  #members can only add video
    )

    name = models.CharField(_(u'name'), max_length=250, unique=True)
    slug = models.SlugField(_(u'slug'), unique=True)
    description = models.TextField(
        _(u'description'),
        blank=True,
        help_text=_('All urls will be converted to links.'))

    logo = S3EnabledImageField(verbose_name=_(u'logo'),
                               blank=True,
                               upload_to='teams/logo/')
    membership_policy = models.IntegerField(_(u'membership policy'),
                                            choices=MEMBERSHIP_POLICY_CHOICES,
                                            default=OPEN)
    video_policy = models.IntegerField(_(u'video policy'),
                                       choices=VIDEO_POLICY_CHOICES,
                                       default=MEMBER_REMOVE)
    is_visible = models.BooleanField(_(u'publicly Visible?'), default=True)
    videos = models.ManyToManyField(Video,
                                    through='TeamVideo',
                                    verbose_name=_('videos'))
    users = models.ManyToManyField(User,
                                   through='TeamMember',
                                   related_name='teams',
                                   verbose_name=_('users'))
    points = models.IntegerField(default=0, editable=False)
    applicants = models.ManyToManyField(User,
                                        through='Application',
                                        related_name='applicated_teams',
                                        verbose_name=_('applicants'))
    invited = models.ManyToManyField(User,
                                     through='Invite',
                                     verbose_name=_('invited'))
    created = models.DateTimeField(auto_now_add=True)
    highlight = models.BooleanField(default=False)
    video = models.ForeignKey(Video,
                              null=True,
                              blank=True,
                              related_name='intro_for_teams',
                              verbose_name=_(u'Intro Video'))
    application_text = models.TextField(blank=True)
    page_content = models.TextField(
        _(u'Page content'),
        blank=True,
        help_text=_(u'You can use murkdown. This will replace Description.'))
    is_moderated = models.BooleanField(default=False)
    header_html_text = models.TextField(
        blank=True,
        default='',
        help_text=_(u"HTML that appears at the top of the teams page."))

    objects = TeamManager()

    class Meta:
        ordering = ['-name']
        verbose_name = _(u'Team')
        verbose_name_plural = _(u'Teams')

    def __unicode__(self):
        return self.name

    def is_open(self):
        return self.membership_policy == self.OPEN

    def is_by_application(self):
        return self.membership_policy == self.APPLICATION

    @classmethod
    def get(cls, slug, user=None, raise404=True):
        if user:
            qs = cls.objects.for_user(user)
        else:
            qs = cls.objects.filter(is_visible=True)
        try:
            return qs.get(slug=slug)
        except cls.DoesNotExist:
            try:
                return qs.get(pk=int(slug))
            except (cls.DoesNotExist, ValueError):
                pass

        if raise404:
            raise Http404

    def logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(100, 100)

    def small_logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(50, 50)

    @models.permalink
    def get_absolute_url(self):
        return ('teams:detail', [self.slug])

    def get_site_url(self):
        return 'http://%s%s' % (Site.objects.get_current().domain,
                                self.get_absolute_url())

    @models.permalink
    def get_edit_url(self):
        return ('teams:edit', [self.slug])

    def is_manager(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user, is_manager=True).exists()

    def is_member(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user).exists()

    def can_remove_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user):
            return True
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return False

    def can_edit_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        return self.can_add_video(user)

    def can_add_video(self, user):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return self.is_manager(user)

    def can_invite(self, user):
        if self.membership_policy == self.INVITATION_BY_MANAGER:
            return self.is_manager(user)

        return self.is_member(user)

    def can_approve_application(self, user):
        return self.is_member(user)

    @property
    def member_count(self):
        if not hasattr(self, '_member_count'):
            setattr(self, '_member_count', self.users.count())
        return self._member_count

    @property
    def videos_count(self):
        if not hasattr(self, '_videos_count'):
            setattr(self, '_videos_count', self.videos.count())
        return self._videos_count

    @property
    def applications_count(self):
        if not hasattr(self, '_applications_count'):
            setattr(self, '_applications_count', self.applications.count())
        return self._applications_count
Esempio n. 7
0
class CustomUser(BaseUser):
    AUTOPLAY_ON_BROWSER = 1
    AUTOPLAY_ON_LANGUAGES = 2
    DONT_AUTOPLAY = 3
    AUTOPLAY_CHOICES = (
        (AUTOPLAY_ON_BROWSER,
         'Autoplay subtitles based on browser preferred languages'),
        (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'),
        (DONT_AUTOPLAY, 'Don\'t autoplay subtitles')
    )
    homepage = models.URLField(blank=True)
    preferred_language = models.CharField(
        max_length=16, choices=ALL_LANGUAGES, blank=True)
    picture = S3EnabledImageField(blank=True, upload_to='pictures/')
    valid_email = models.BooleanField(default=False)

    # if true, items that end on the user activity stream will also be
    # sent as email
    notify_by_email= models.BooleanField(default=True)
    # if true, items that end on the user activity stream will also be
    # sent as a message
    notify_by_message = models.BooleanField(default=True)
    biography = models.TextField('Bio', blank=True)
    autoplay_preferences = models.IntegerField(
        choices=AUTOPLAY_CHOICES, default=AUTOPLAY_ON_BROWSER)
    award_points = models.IntegerField(default=0)
    last_ip = models.IPAddressField(blank=True, null=True)
    # videos witch are related to user. this is for quicker queries
    videos = models.ManyToManyField('videos.Video', blank=True)
    # for some login backends we end up with a full name but not
    # a first name, last name pair.
    full_name = models.CharField(max_length=63, blank=True, default='')
    partner = models.ForeignKey('teams.Partner', blank=True, null=True)
    is_partner = models.BooleanField(default=False)
    pay_rate_code = models.CharField(max_length=3, blank=True, default='')
    can_send_messages = models.BooleanField(default=True)
    show_tutorial = models.BooleanField(default=True)
    created_by = models.ForeignKey('self', null=True, blank=True,
                                   related_name='created_users')

    objects = CustomUserManager()

    cache = ModelCacheManager(default_cache_pattern='user')

    class Meta:
        verbose_name = 'User'

    def __unicode__(self):
        if not self.is_active:
            return ugettext('Retired user')

        if self.first_name or self.last_name:
            return self.get_full_name()
        elif self.full_name:
            return self.full_name
        else:
            return self.username

    def has_fullname_set(self):
        return any([self.first_name, self.last_name, self.full_name])

    def display_name(self):
        if self.has_fullname_set():
            return u'{} ({})'.format(unicode(self), self.username)
        else:
            return unicode(self.username)

    def save(self, *args, **kwargs):
        send_confirmation = False

        if not self.email:
            self.valid_email = False
        elif self.pk:
            try:
                before_save = self.__class__._default_manager.get(pk=self.pk)
                send_confirmation = before_save.email != self.email
            except models.ObjectDoesNotExist:
                send_confirmation = True
        elif self.email:
            send_confirmation = True

        if send_confirmation:
            self.valid_email = False

        send_email_confirmation = kwargs.pop('send_email_confirmation', True)
        super(CustomUser, self).save(*args, **kwargs)

        if send_confirmation and send_email_confirmation:
            EmailConfirmation.objects.send_confirmation(self)

    def unread_messages(self, hidden_meassage_id=None):
        from messages.models import Message

        qs = Message.objects.for_user(self).filter(read=False)

        try:
            if hidden_meassage_id:
                qs = qs.filter(pk__gt=hidden_meassage_id)
        except (ValueError, TypeError):
            pass

        return qs

    def unread_messages_count(self, hidden_meassage_id=None):
        return self.unread_messages(hidden_meassage_id).count()

    @classmethod
    def tutorial_was_shown(self, id):
        self.objects.filter(pk=id).update(show_tutorial=False)

    @classmethod
    def displayable_users(self, ids):
        return self.objects.filter(pk__in=ids).values_list('pk', 'first_name', 'last_name', 'username')

    @classmethod
    def video_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs):
        from videos.models import SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for video_pk in pk_set:
                cls.videos.through.objects.get_or_create(video__pk=video_pk, customuser=instance, defaults={'video_id': video_pk})
        elif reverse and action == 'post_remove':
            #instance is User
            for video_pk in pk_set:
                if not SubtitleLanguage.objects.filter(followers=instance, video__pk=video_pk).exists():
                    instance.videos.remove(video_pk)
        elif not reverse and action == 'post_add':
            #instance is Video
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(video=instance, customuser__pk=user_pk, defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is Video
            for user_pk in pk_set:
                if not SubtitleLanguage.objects.filter(followers__pk=user_pk, video=instance).exists():
                    instance.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is Video
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance).delete()

    @classmethod
    def sl_followers_change_handler(cls, sender, instance, action, reverse, model, pk_set, **kwargs):
        from videos.models import Video, SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for sl_pk in pk_set:
                sl = SubtitleLanguage.objects.get(pk=sl_pk)
                cls.videos.through.objects.get_or_create(video=sl.video, customuser=instance)
        elif reverse and action == 'post_remove':
            #instance is User
            for sl_pk in pk_set:
                if not Video.objects.filter(followers=instance, subtitlelanguage__pk=sl_pk).exists():
                    sl = SubtitleLanguage.objects.get(pk=sl_pk)
                    instance.videos.remove(sl.video)
        elif not reverse and action == 'post_add':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(video=instance.video, customuser__pk=user_pk, defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                if not Video.objects.filter(followers__pk=user_pk, subtitlelanguage=instance).exists():
                    instance.video.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is SubtitleLanguage
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance.video).delete()

    def get_languages(self):
        """Get a list of language codes that the user speaks."""
        return self.cache.get_or_calc("languages", self.calc_languages)

    def calc_languages(self):
        return list(self.userlanguage_set.order_by("priority").values_list('language', flat=True))

    def set_languages(self, languages):
        with transaction.commit_on_success():
            self.userlanguage_set.all().delete()
            self.userlanguage_set = [
                UserLanguage(language=l["language"],
                             priority=l["priority"])
                for l in languages
            ]
        self.cache.invalidate()

    def get_language_names(self):
        """Get a list of language names that the user speaks."""
        return [translation.get_language_label(lc)
                for lc in self.get_languages()]

    def get_language_codes_and_names(self):
        """Get a list of language codes/names that the user speaks."""
        return [(lc, translation.get_language_label(lc))
                for lc in self.get_languages()]

    def speaks_language(self, language_code):
        return language_code in [l.language for l in self.get_languages()]

    def is_team_manager(self):
        cached_value = self.cache.get('is-manager')
        if cached_value is not None:
            return cached_value
        is_manager = self.managed_teams().exists()
        self.cache.set('is-manager', is_manager)
        return is_manager

    def managed_teams(self, include_manager=True):
        from teams.models import TeamMember
        possible_roles = [TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN]
        if include_manager:
            possible_roles.append(TeamMember.ROLE_MANAGER)
        return self.teams.filter(members__role__in=possible_roles)

    def messageable_teams(self):
        from teams.models import Team
        from teams.permissions import can_message_all_members

        teams = self.teams.all()
        messageable_team_ids = [t.id for t in teams if can_message_all_members(t, self)]

        partners = self.managed_partners.all()
        teams = [list(p.teams.all()) for p in partners]
        partner_teams_ids = [team.id for qs in teams for team in qs]

        messageable_team_ids = messageable_team_ids + partner_teams_ids
        return Team.objects.filter(id__in=messageable_team_ids)

    def open_tasks(self):
        from teams.models import Task
        return Task.objects.incomplete().filter(assignee=self)

    def _get_gravatar(self, size):
        url = "http://www.gravatar.com/avatar/" + hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() + "?"
        url += urllib.urlencode({'d': 'mm', 's':str(size)})
        return url

    def _get_avatar_by_size(self, size):
        if self.picture:
            return self.picture.thumb_url(size, size)
        else:
            return self._get_gravatar(size)
    def avatar(self):
        return self._get_avatar_by_size(100)

    def small_avatar(self):
        return self._get_avatar_by_size(50)

    @models.permalink
    def get_absolute_url(self):
        return ('profiles:profile', [urlquote(self.username)])

    def send_message_url(self):
        return '{}?user={}'.format(reverse('messages:new'),
                                   urlquote(self.username))

    @property
    def language(self):
        return self.get_preferred_language_display()

    def guess_best_lang(self, request=None):

        if self.preferred_language:
            return self.preferred_language

        user_languages = list(self.userlanguage_set.all())
        if user_languages:
            return user_languages[0].language

        if request:
            languages = translation.get_user_languages_from_request(request)
            if languages:
                return languages[0]

        return 'en'

    def guess_is_rtl(self, request=None):
        return translation.is_rtl(self.guess_best_lang(request))

    @models.permalink
    def profile_url(self):
        return ('profiles:profile', [self.pk])

    def hash_for_video(self, video_id):
        return hashlib.sha224(settings.SECRET_KEY+str(self.pk)+video_id).hexdigest()

    @classmethod
    def get_anonymous(cls):
        user, created = cls.objects.get_or_create(
            pk=settings.ANONYMOUS_USER_ID,
            defaults={'username': '******'})
        return user

    @property
    def is_anonymous(self):
        return self.pk == settings.ANONYMOUS_USER_ID

    @property
    def is_external(self):
        """
        Checks whether accout is external
        It can me an OpeenId link or a token stored as
        a ThirdPartyAccount
        """
        try:
            l = self.openid_connect_link
            return True
        except:
            from thirdpartyaccounts import get_thirdpartyaccount_types
            for thirdpartyaccount_type in get_thirdpartyaccount_types():
                m = get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1])
                if (m is not None) and (len(m.objects.for_user(self)) > 0):
                    return True
        return False

    def has_valid_password(self):
        return len(self.password) > 0 and self.has_usable_password()

    def unlink_external(self):
        from thirdpartyaccounts import get_thirdpartyaccount_types
        for thirdpartyaccount_type in get_thirdpartyaccount_types():
            m = get_model(thirdpartyaccount_type[0], thirdpartyaccount_type[1])
            if m is not None:
                m.objects.for_user(self).delete()
        from socialauth.models import AuthMeta, OpenidProfile
        AuthMeta.objects.filter(user=self).delete()
        OpenidProfile.objects.filter(user=self).delete()
        try:
            self.openid_connect_link.delete()
        except:
            pass

    def get_api_key(self):
        return ApiKey.objects.get_or_create(user=self)[0].key

    def ensure_api_key_created(self):
        ApiKey.objects.get_or_create(user=self)
Esempio n. 8
0
class CustomUser(BaseUser):
    AUTOPLAY_ON_BROWSER = 1
    AUTOPLAY_ON_LANGUAGES = 2
    DONT_AUTOPLAY = 3
    AUTOPLAY_CHOICES = (
        (AUTOPLAY_ON_BROWSER,
         'Autoplay subtitles based on browser preferred languages'),
        (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'),
        (DONT_AUTOPLAY, 'Don\'t autoplay subtitles'))
    homepage = models.URLField(blank=True)
    preferred_language = models.CharField(max_length=16,
                                          choices=ALL_LANGUAGES,
                                          blank=True)
    picture = S3EnabledImageField(blank=True, upload_to='pictures/')
    valid_email = models.BooleanField(default=False)

    # if true, items that end on the user activity stream will also be
    # sent as email
    notify_by_email = models.BooleanField(default=True)
    # if true, items that end on the user activity stream will also be
    # sent as a message
    notify_by_message = models.BooleanField(default=True)
    biography = models.TextField('Bio', blank=True)
    autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES,
                                               default=AUTOPLAY_ON_BROWSER)
    award_points = models.IntegerField(default=0)
    last_ip = models.IPAddressField(blank=True, null=True)
    # videos witch are related to user. this is for quicker queries
    videos = models.ManyToManyField('videos.Video', blank=True)
    # for some login backends we end up with a full name but not
    # a first name, last name pair.
    full_name = models.CharField(max_length=63, blank=True, default='')
    partner = models.ForeignKey('teams.Partner', blank=True, null=True)
    is_partner = models.BooleanField(default=False)
    pay_rate_code = models.CharField(max_length=3, blank=True, default='')
    can_send_messages = models.BooleanField(default=True)
    third_party_accounts = models.ManyToManyField(
        "accountlinker.ThirdPartyAccount",
        related_name='users',
        verbose_name=_('third party accounts'))

    objects = UserManager()

    class Meta:
        verbose_name = 'User'

    def __unicode__(self):
        if not self.is_active:
            return ugettext('Retired user')

        if self.first_name:
            if self.last_name:
                return self.get_full_name()
            else:
                return self.first_name
        if self.full_name:
            return self.full_name
        return self.username

    def save(self, *args, **kwargs):
        send_confirmation = False

        if not self.email:
            self.valid_email = False
        elif self.pk:
            try:
                before_save = self.__class__._default_manager.get(pk=self.pk)
                send_confirmation = before_save.email != self.email
            except models.ObjectDoesNotExist:
                send_confirmation = True
        elif self.email:
            send_confirmation = True

        if send_confirmation:
            self.valid_email = False

        send_email_confirmation = kwargs.pop('send_email_confirmation', True)
        super(CustomUser, self).save(*args, **kwargs)

        if send_confirmation and send_email_confirmation:
            EmailConfirmation.objects.send_confirmation(self)

    def unread_messages(self, hidden_meassage_id=None):
        from messages.models import Message

        qs = Message.objects.for_user(self).filter(read=False)

        try:
            if hidden_meassage_id:
                qs = qs.filter(pk__gt=hidden_meassage_id)
        except (ValueError, TypeError):
            pass

        return qs

    def unread_messages_count(self, hidden_meassage_id=None):
        if not hasattr(self, '_unread_messages_count'):
            self._unread_messages_count = self.unread_messages(
                hidden_meassage_id=hidden_meassage_id).count()
        return self._unread_messages_count

    @classmethod
    def video_followers_change_handler(cls, sender, instance, action, reverse,
                                       model, pk_set, **kwargs):
        from videos.models import SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for video_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video__pk=video_pk,
                    customuser=instance,
                    defaults={'video_id': video_pk})
        elif reverse and action == 'post_remove':
            #instance is User
            for video_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers=instance, video__pk=video_pk).exists():
                    instance.videos.remove(video_pk)
        elif not reverse and action == 'post_add':
            #instance is Video
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is Video
            for user_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers__pk=user_pk, video=instance).exists():
                    instance.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is Video
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance).delete()

    @classmethod
    def sl_followers_change_handler(cls, sender, instance, action, reverse,
                                    model, pk_set, **kwargs):
        from videos.models import Video, SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for sl_pk in pk_set:
                sl = SubtitleLanguage.objects.get(pk=sl_pk)
                cls.videos.through.objects.get_or_create(video=sl.video,
                                                         customuser=instance)
        elif reverse and action == 'post_remove':
            #instance is User
            for sl_pk in pk_set:
                if not Video.objects.filter(
                        followers=instance,
                        subtitlelanguage__pk=sl_pk).exists():
                    sl = SubtitleLanguage.objects.get(pk=sl_pk)
                    instance.videos.remove(sl.video)
        elif not reverse and action == 'post_add':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance.video,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                if not Video.objects.filter(
                        followers__pk=user_pk,
                        subtitlelanguage=instance).exists():
                    instance.video.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is SubtitleLanguage
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance.video).delete()

    def get_languages(self):
        """
        Just to control this query
        """
        languages = cache.get('user_languages_%s' % self.pk)

        if languages is None:
            languages = self.userlanguage_set.all()
            cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7)

        return languages

    def speaks_language(self, language_code):
        return language_code in [l.language for l in self.get_languages()]

    def managed_teams(self):
        from apps.teams.models import TeamMember
        return self.teams.filter(members__role__in=[
            TeamMember.ROLE_OWNER, TeamMember.ROLE_ADMIN,
            TeamMember.ROLE_MANAGER
        ])

    def messageable_teams(self):
        from apps.teams.models import Team
        from apps.teams.permissions import can_message_all_members

        teams = self.teams.all()
        messageable_team_ids = [
            t.id for t in teams if can_message_all_members(t, self)
        ]

        partners = self.managed_partners.all()
        teams = [list(p.teams.all()) for p in partners]
        partner_teams_ids = [team.id for qs in teams for team in qs]

        messageable_team_ids = messageable_team_ids + partner_teams_ids
        return Team.objects.filter(id__in=messageable_team_ids)

    def open_tasks(self):
        from apps.teams.models import Task
        return Task.objects.incomplete().filter(assignee=self)

    def _get_gravatar(self, size):
        url = "http://www.gravatar.com/avatar/" + hashlib.md5(
            self.email.lower().encode('utf-8')).hexdigest() + "?"
        url += urllib.urlencode({'d': 'mm', 's': str(size)})
        return url

    def _get_avatar_by_size(self, size):
        if self.picture:
            return self.picture.thumb_url(size, size)
        else:
            return self._get_gravatar(size)

    def avatar(self):
        return self._get_avatar_by_size(100)

    def small_avatar(self):
        return self._get_avatar_by_size(50)

    @models.permalink
    def get_absolute_url(self):
        return ('profiles:profile', [urlquote(self.username)])

    @property
    def language(self):
        return self.get_preferred_language_display()

    def guess_best_lang(self, request=None):

        if self.preferred_language:
            return self.preferred_language

        user_languages = list(self.userlanguage_set.all())
        if user_languages:
            return user_languages[0].language

        from utils.translation import get_user_languages_from_request

        if request:
            languages = get_user_languages_from_request(request)
            if languages:
                return languages[0]

        return 'en'

    def guess_is_rtl(self, request=None):
        from utils.translation import is_rtl
        return is_rtl(self.guess_best_lang(request))

    @models.permalink
    def profile_url(self):
        return ('profiles:profile', [self.pk])

    def hash_for_video(self, video_id):
        return hashlib.sha224(settings.SECRET_KEY + str(self.pk) +
                              video_id).hexdigest()

    @classmethod
    def get_anonymous(cls):
        try:
            return cls.objects.get(pk=settings.ANONYMOUS_USER_ID)
        except cls.DoesNotExist:
            return None

    @property
    def is_anonymous(self):
        return self.pk == settings.ANONYMOUS_USER_ID

    def get_api_key(self):
        return ApiKey.objects.get_or_create(user=self)[0].key
Esempio n. 9
0
class CustomUser(BaseUser):
    AUTOPLAY_ON_BROWSER = 1
    AUTOPLAY_ON_LANGUAGES = 2
    DONT_AUTOPLAY = 3
    AUTOPLAY_CHOICES = (
        (AUTOPLAY_ON_BROWSER,
         'Autoplay subtitles based on browser preferred languages'),
        (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'),
        (DONT_AUTOPLAY, 'Don\'t autoplay subtitles'))
    homepage = models.URLField(verify_exists=False, blank=True)
    preferred_language = models.CharField(max_length=16,
                                          choices=ALL_LANGUAGES,
                                          blank=True)
    picture = S3EnabledImageField(blank=True, upload_to='pictures/')
    valid_email = models.BooleanField(default=False)
    changes_notification = models.BooleanField(default=True)
    follow_new_video = models.BooleanField(default=True)
    biography = models.TextField('Tell us about yourself', blank=True)
    autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES,
                                               default=AUTOPLAY_ON_BROWSER)
    award_points = models.IntegerField(default=0)
    last_ip = models.IPAddressField(blank=True, null=True)
    #videos witch are related to user. this is for quicker queries
    videos = models.ManyToManyField('videos.Video', blank=True)

    objects = UserManager()

    class Meta:
        verbose_name = 'User'

    def __unicode__(self):
        if not self.is_active:
            return ugettext('Retired user')

        if self.first_name:
            if self.last_name:
                return self.get_full_name()
            else:
                return self.first_name
        return self.username

    def unread_messages(self):
        from messages.models import Message

        return Message.objects.for_user(self).filter(read=False)

    @classmethod
    def video_followers_change_handler(cls, sender, instance, action, reverse,
                                       model, pk_set, **kwargs):
        from videos.models import SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for video_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video__pk=video_pk,
                    customuser=instance,
                    defaults={'video_id': video_pk})
        elif reverse and action == 'post_remove':
            #instance is User
            for video_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers=instance, video__pk=video_pk).exists():
                    instance.videos.remove(video_pk)
        elif not reverse and action == 'post_add':
            #instance is Video
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is Video
            for user_pk in pk_set:
                if not SubtitleLanguage.objects.filter(
                        followers__pk=user_pk, video=instance).exists():
                    instance.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is Video
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance).delete()

    @classmethod
    def sl_followers_change_handler(cls, sender, instance, action, reverse,
                                    model, pk_set, **kwargs):
        from videos.models import Video, SubtitleLanguage

        if reverse and action == 'post_add':
            #instance is User
            for sl_pk in pk_set:
                sl = SubtitleLanguage.objects.get(pk=sl_pk)
                cls.videos.through.objects.get_or_create(video=sl.video,
                                                         customuser=instance)
        elif reverse and action == 'post_remove':
            #instance is User
            for sl_pk in pk_set:
                if not Video.objects.filter(
                        followers=instance,
                        subtitlelanguage__pk=sl_pk).exists():
                    sl = SubtitleLanguage.objects.get(pk=sl_pk)
                    instance.videos.remove(sl.video)
        elif not reverse and action == 'post_add':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                cls.videos.through.objects.get_or_create(
                    video=instance.video,
                    customuser__pk=user_pk,
                    defaults={'customuser_id': user_pk})
        elif not reverse and action == 'post_remove':
            #instance is SubtitleLanguage
            for user_pk in pk_set:
                if not Video.objects.filter(
                        followers__pk=user_pk,
                        subtitlelanguage=instance).exists():
                    instance.video.customuser_set.remove(user_pk)
        elif reverse and action == 'post_clear':
            #instance is User
            cls.videos.through.objects.filter(customuser=instance) \
                .exclude(video__subtitlelanguage__followers=instance).delete()
        elif not reverse and action == 'post_clear':
            #instance is SubtitleLanguage
            cls.videos.through.objects.filter(video=instance) \
                .exclude(customuser__followed_languages__video=instance.video).delete()

    def get_languages(self):
        """
        Just to control this query
        """
        languages = cache.get('user_languages_%s' % self.pk)

        if languages is None:
            languages = self.userlanguage_set.all()
            cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7)

        return languages

    def speaks_language(self, language_code):
        return language_code in [l.language for l in self.get_languages()]

    def managed_teams(self):
        return self.teams.filter(members__is_manager=True)

    def _get_gravatar(self, size):
        url = "http://www.gravatar.com/avatar/" + hashlib.md5(
            self.email.lower()).hexdigest() + "?"
        url += urllib.urlencode({'d': 'mm', 's': str(size)})
        return url

    def _get_avatar_by_size(self, size):
        if self.picture:
            return self.picture.thumb_url(size, size)
        else:
            return self._get_gravatar(size)

    def avatar(self):
        return self._get_avatar_by_size(100)

    def small_avatar(self):
        return self._get_avatar_by_size(50)

    @models.permalink
    def get_absolute_url(self):
        return ('profiles:profile', [urlquote_plus(self.username)])

    @property
    def language(self):
        return self.get_preferred_language_display()

    @models.permalink
    def profile_url(self):
        return ('profiles:profile', [self.pk])

    def hash_for_video(self, video_id):
        return hashlib.sha224(settings.SECRET_KEY + str(self.pk) +
                              video_id).hexdigest()

    @classmethod
    def get_youtube_anonymous(cls):
        return cls.objects.get(pk=10000)
Esempio n. 10
0
class Team(models.Model):
    APPLICATION = 1
    INVITATION_BY_MANAGER = 2
    INVITATION_BY_ALL = 3
    OPEN = 4
    MEMBERSHIP_POLICY_CHOICES = (
        (APPLICATION, _(u'Application')),
        (INVITATION_BY_MANAGER, _(u'Invitation by manager')),
        (INVITATION_BY_ALL, _(u'Invitation by any member')),
        (OPEN, _(u'Open')),
    )
    MEMBER_REMOVE = 1
    MANAGER_REMOVE = 2
    MEMBER_ADD = 3
    VIDEO_POLICY_CHOICES = (
        (MEMBER_REMOVE, _(u'Members can add and remove video')
         ),  #any member can add/delete video
        (MANAGER_REMOVE, _(u'Managers can add and remove video')
         ),  #only managers can add/remove video
        (MEMBER_ADD, _(u'Members can only add videos')
         )  #members can only add video
    )

    name = models.CharField(_(u'name'), max_length=250, unique=True)
    slug = models.SlugField(_(u'slug'), unique=True)
    description = models.TextField(
        _(u'description'),
        blank=True,
        help_text=_('All urls will be converted to links.'))

    logo = S3EnabledImageField(verbose_name=_(u'logo'),
                               blank=True,
                               upload_to='teams/logo/')
    membership_policy = models.IntegerField(_(u'membership policy'),
                                            choices=MEMBERSHIP_POLICY_CHOICES,
                                            default=OPEN)
    video_policy = models.IntegerField(_(u'video policy'),
                                       choices=VIDEO_POLICY_CHOICES,
                                       default=MEMBER_REMOVE)
    is_visible = models.BooleanField(_(u'publicly Visible?'), default=True)
    videos = models.ManyToManyField(Video,
                                    through='TeamVideo',
                                    verbose_name=_('videos'))
    users = models.ManyToManyField(User,
                                   through='TeamMember',
                                   related_name='teams',
                                   verbose_name=_('users'))
    points = models.IntegerField(default=0, editable=False)
    applicants = models.ManyToManyField(User,
                                        through='Application',
                                        related_name='applicated_teams',
                                        verbose_name=_('applicants'))
    invited = models.ManyToManyField(User,
                                     through='Invite',
                                     verbose_name=_('invited'))
    created = models.DateTimeField(auto_now_add=True)
    highlight = models.BooleanField(default=False)
    video = models.ForeignKey(Video,
                              null=True,
                              blank=True,
                              related_name='intro_for_teams',
                              verbose_name=_(u'Intro Video'))
    application_text = models.TextField(blank=True)
    page_content = models.TextField(
        _(u'Page content'),
        blank=True,
        help_text=_(u'You can use murkdown. This will replace Description.'))
    is_moderated = models.BooleanField(default=False)
    header_html_text = models.TextField(
        blank=True,
        default='',
        help_text=_(u"HTML that appears at the top of the teams page."))

    objects = TeamManager()

    class Meta:
        ordering = ['-name']
        verbose_name = _(u'Team')
        verbose_name_plural = _(u'Teams')

    def __unicode__(self):
        return self.name

    def is_open(self):
        return self.membership_policy == self.OPEN

    def is_by_application(self):
        return self.membership_policy == self.APPLICATION

    @classmethod
    def get(cls, slug, user=None, raise404=True):
        if user:
            qs = cls.objects.for_user(user)
        else:
            qs = cls.objects.filter(is_visible=True)
        try:
            return qs.get(slug=slug)
        except cls.DoesNotExist:
            try:
                return qs.get(pk=int(slug))
            except (cls.DoesNotExist, ValueError):
                pass

        if raise404:
            raise Http404

    def logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(100, 100)

    def small_logo_thumbnail(self):
        if self.logo:
            return self.logo.thumb_url(50, 50)

    @models.permalink
    def get_absolute_url(self):
        return ('teams:detail', [self.slug])

    def get_site_url(self):
        return 'http://%s%s' % (Site.objects.get_current().domain,
                                self.get_absolute_url())

    @models.permalink
    def get_edit_url(self):
        return ('teams:edit', [self.slug])

    def is_manager(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user, is_manager=True).exists()

    def is_member(self, user):
        if not user.is_authenticated():
            return False
        return self.members.filter(user=user).exists()

    def can_remove_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MANAGER_REMOVE and self.is_manager(user):
            return True
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return False

    def can_edit_video(self, user, team_video=None):
        if not user.is_authenticated():
            return False
        return self.can_add_video(user)

    def can_add_video(self, user):
        if not user.is_authenticated():
            return False
        if self.video_policy == self.MEMBER_REMOVE and self.is_member(user):
            return True
        return self.is_manager(user)

    def can_invite(self, user):
        if self.membership_policy == self.INVITATION_BY_MANAGER:
            return self.is_manager(user)

        return self.is_member(user)

    def can_approve_application(self, user):
        return self.is_member(user)

    @property
    def member_count(self):
        if not hasattr(self, '_member_count'):
            setattr(self, '_member_count', self.users.count())
        return self._member_count

    @property
    def videos_count(self):
        if not hasattr(self, '_videos_count'):
            setattr(self, '_videos_count', self.videos.count())
        return self._videos_count

    @property
    def applications_count(self):
        if not hasattr(self, '_applications_count'):
            setattr(self, '_applications_count', self.applications.count())
        return self._applications_count

    def get_videos_for_languages(self, languages,
                                 CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS):
        from utils.multy_query_set import TeamMultyQuerySet
        languages.extend(
            [l[:l.find('-')] for l in languages if l.find('-') > -1])

        langs_pairs = []

        for l1 in languages:
            for l0 in languages:
                if not l1 == l0:
                    langs_pairs.append('%s_%s' % (l1, l0))

        qs = TeamVideoLanguagePair.objects.filter(language_pair__in=langs_pairs, team=self) \
            .select_related('team_video', 'team_video__video')
        lqs = TeamVideoLanguage.objects.filter(team=self).select_related(
            'team_video', 'team_video__video')

        qs1 = qs.filter(percent_complete__gt=0, percent_complete__lt=100)
        qs2 = qs.filter(percent_complete=0)
        qs3 = lqs.filter(is_original=True,
                         is_complete=False,
                         language__in=languages)
        qs4 = lqs.filter(is_original=False,
                         forked=True,
                         is_complete=False,
                         language__in=languages)
        mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4)

        total_count = TeamVideo.objects.filter(team=self).count()

        additional = TeamVideoLanguagePair.objects.none()
        all_videos = TeamVideo.objects.filter(
            team=self).select_related('video')

        if total_count == 0:
            mqs = all_videos
        else:
            if total_count < CUTTOFF_DUPLICATES_NUM_VIDEOS_ON_TEAMS:
                additional = all_videos.exclude(pk__in=[x.id for x in mqs])
            else:
                additional = all_videos
            mqs = TeamMultyQuerySet(qs1, qs2, qs3, qs4, additional)

        return {
            'qs': qs,
            'lqs': lqs,
            'qs1': qs1,
            'qs2': qs2,
            'qs3': qs3,
            'qs4': qs4,
            'videos': mqs,
            'videos_count': len(mqs),
            'additional_count': additional.count(),
            'additional': additional[:50],
            'lqs': lqs,
            'qs': qs,
        }
Esempio n. 11
0
class CustomUser(BaseUser):
    AUTOPLAY_ON_BROWSER = 1
    AUTOPLAY_ON_LANGUAGES = 2
    DONT_AUTOPLAY = 3
    AUTOPLAY_CHOICES = (
        (AUTOPLAY_ON_BROWSER,
         'Autoplay subtitles based on browser preferred languages'),
        (AUTOPLAY_ON_LANGUAGES, 'Autoplay subtitles in languages I know'),
        (DONT_AUTOPLAY, 'Don\'t autoplay subtitles'))
    homepage = models.URLField(verify_exists=False, blank=True)
    preferred_language = models.CharField(max_length=16,
                                          choices=ALL_LANGUAGES,
                                          blank=True)
    picture = S3EnabledImageField(blank=True, upload_to='pictures/')
    valid_email = models.BooleanField(default=False)
    changes_notification = models.BooleanField(default=True)
    biography = models.TextField('Tell us about yourself', blank=True)
    autoplay_preferences = models.IntegerField(choices=AUTOPLAY_CHOICES,
                                               default=AUTOPLAY_ON_BROWSER)
    award_points = models.IntegerField(default=0)
    last_ip = models.IPAddressField(blank=True, null=True)

    objects = UserManager()

    class Meta:
        verbose_name = 'User'

    def __unicode__(self):
        if not self.is_active:
            return ugettext('Anonymous')

        if self.first_name:
            if self.last_name:
                return self.get_full_name()
            else:
                return self.first_name
        return self.username

    def get_languages(self):
        """
        Just to control this query
        """
        languages = cache.get('user_languages_%s' % self.pk)

        if languages is None:
            languages = self.userlanguage_set.all()
            cache.set('user_languages_%s' % self.pk, languages, 60 * 24 * 7)

        return languages

    def managed_teams(self):
        return self.teams.filter(members__is_manager=True)

    def avatar(self):
        return self.picture.thumb_url(100, 100)

    def small_avatar(self):
        return self.picture.thumb_url(50, 50)

    @models.permalink
    def get_absolute_url(self):
        return ('profiles:profile', [urlquote_plus(self.username)])

    @property
    def language(self):
        return self.get_preferred_language_display()

    @models.permalink
    def profile_url(self):
        return ('profiles:profile', [self.pk])

    def hash_for_video(self, video_id):
        return hashlib.sha224(settings.SECRET_KEY + str(self.pk) +
                              video_id).hexdigest()

    @classmethod
    def get_youtube_anonymous(cls):
        return cls.objects.get(pk=10000)
Esempio n. 12
0
class TeamVideo(models.Model):
    team = models.ForeignKey(Team)
    video = models.ForeignKey(Video)
    title = models.CharField(max_length=2048, blank=True)
    description = models.TextField(
        blank=True,
        help_text=
        _(u'Use this space to explain why you or your team need to caption or subtitle this video. Adding a note makes volunteers more likely to help out!'
          ))
    thumbnail = S3EnabledImageField(
        upload_to='teams/video_thumbnails/',
        null=True,
        blank=True,
        help_text=_(
            u'We automatically grab thumbnails for certain sites, e.g. Youtube'
        ))
    all_languages = models.BooleanField(
        _('Need help with all languages'),
        default=False,
        help_text=_(
            'If you check this, other languages will not be displayed.'))
    added_by = models.ForeignKey(User)
    completed_languages = models.ManyToManyField(SubtitleLanguage, blank=True)

    class Meta:
        unique_together = (('team', 'video'), )

    def __unicode__(self):
        return self.title or self.video.__unicode__()

    def save(self, *args, **kwargs):
        created = bool(not self.pk)
        super(TeamVideo, self).save(*args, **kwargs)
        #asynchronous call
        if created:
            update_one_team_video.delay(self.id)

    def can_remove(self, user):
        return self.team.can_remove_video(user, self)

    def can_edit(self, user):
        return self.team.can_edit_video(user, self)

    def link_to_page(self):
        if self.all_languages:
            return self.video.get_absolute_url()
        return self.video.video_link()

    @models.permalink
    def get_absolute_url(self):
        return ('teams:team_video', [self.pk])

    def get_thumbnail(self):
        if self.thumbnail:
            return self.thumbnail.thumb_url(100, 100)

        if self.video.thumbnail:
            th = self.video.get_thumbnail()
            if th:
                return th

        if self.team.logo:
            return self.team.logo_thumbnail()

        return ''

    def _calculate_percent_complete(self, sl0, sl1):
        # maybe move this to Video model in future.
        if not sl0 or not sl0.is_dependable():
            return -1
        if not sl1:
            return 0
        if sl1.is_dependent():
            if sl1.percent_done == 0:
                return 0
            elif sl0.is_dependent():
                l_dep0 = sl0.real_standard_language()
                l_dep1 = sl1.real_standard_language()
                if l_dep0 and l_dep1 and l_dep0.id == l_dep1.id:
                    return sl1.percent_done
                else:
                    return -1
            else:
                l_dep1 = sl1.real_standard_language()
                return sl1.percent_done if \
                    l_dep1 and l_dep1.id == sl0.id else -1
        else:
            sl1_subtitle_count = 0
            latest_version = sl1.latest_version()
            if latest_version:
                sl1_subtitle_count = latest_version.subtitle_set.count()
            return 0 if sl1_subtitle_count == 0 else -1

    def _update_team_video_language_pair(self, lang0, sl0, lang1, sl1):
        percent_complete = self._calculate_percent_complete(sl0, sl1)
        if sl1 is not None:
            tvlps = TeamVideoLanguagePair.objects.filter(
                team_video=self,
                subtitle_language_0=sl0,
                subtitle_language_1=sl1)
        else:
            tvlps = TeamVideoLanguagePair.objects.filter(
                team_video=self, subtitle_language_0=lang0, language_1=lang1)
        tvlp = None if len(tvlps) == 0 else tvlps[0]
        if not tvlp and percent_complete != -1:
            tvlp = TeamVideoLanguagePair(team_video=self,
                                         team=self.team,
                                         video=self.video,
                                         language_0=lang0,
                                         subtitle_language_0=sl0,
                                         language_1=lang1,
                                         subtitle_language_1=sl1,
                                         language_pair='{0}_{1}'.format(
                                             lang0, lang1),
                                         percent_complete=percent_complete)
            tvlp.save()
        elif tvlp and percent_complete != -1:
            tvlp.percent_complete = percent_complete
            tvlp.save()
        elif tvlp and percent_complete == -1:
            tvlp.remove()

    def _update_tvlp_for_languages(self, lang0, lang1, langs):
        sl0_list = langs[lang0]
        sl1_list = langs[lang1]
        if len(sl1_list) == 0:
            sl1_list = [None]
        for sl0 in sl0_list:
            for sl1 in sl1_list:
                self._update_team_video_language_pair(lang0, sl0, lang1, sl1)

    def _subtitle_language_multivalue_dict(self):
        langs = {}
        for sl in self.video.subtitlelanguage_set.all():
            if not sl.language:
                continue
            if sl.language in langs:
                langs[sl.language].append(sl)
            else:
                langs[sl.language] = [sl]
        return langs

    def update_team_video_language_pairs(self, lang_code_list=None):
        TeamVideoLanguagePair.objects.filter(team_video=self).delete()
        if lang_code_list is None:
            lang_code_list = [item[0] for item in settings.ALL_LANGUAGES]
        langs = self._subtitle_language_multivalue_dict()
        for lang0, sl0_list in langs.items():
            for lang1 in lang_code_list:
                if lang0 == lang1:
                    continue
                self._update_tvlp_for_languages(lang0, lang1, langs)

    def update_team_video_language_pairs_for_sl(self, sl):
        if not sl.language:
            return

        lang_code_list = [item[0] for item in settings.ALL_LANGUAGES]

        TeamVideoLanguagePair.objects.filter(team_video=self,
                                             subtitle_language_0=sl).delete()
        TeamVideoLanguagePair.objects.filter(team_video=self,
                                             subtitle_language_1=sl).delete()
        TeamVideoLanguagePair.objects.filter(team_video=self,
                                             subtitle_language_1__is_null=True,
                                             language_1=sl.language).delete()

        langs = self._subtitle_language_multivalue_dict()

        for lang in lang_code_list:
            sl1_list = langs[lang]
            if len(sl1_list) == 0:
                sl1_list = [None]
                for sl1 in sl1_list:
                    self._update_team_video_language_pair(
                        sl.language, sl, lang, sl1)
        for sl0 in self.video.subtitlelanguage_set.all():
            self._update_team_video_language_pair(sl0.language, sl0,
                                                  sl.language, sl)