示例#1
0
class ProjectMedia(ModelBase):
    video_mimetypes = (
        'video/ogg',
        'video/webm',
        'video/mp4',
        'application/ogg',
        'audio/ogg',
    )
    image_mimetypes = (
        'image/png',
        'image/jpg',
        'image/jpeg',
        'image/gif',
    )
    accepted_mimetypes = video_mimetypes + image_mimetypes
    project_file = models.FileField(upload_to=determine_media_upload_path)
    project = models.ForeignKey(Project)
    mime_type = models.CharField(max_length=80, null=True)
    thumbnail = models.ImageField(upload_to=determine_image_upload_path,
                                  null=True,
                                  blank=True,
                                  storage=storage.ImageStorage())

    def thumbnail_or_default(self):
        """Return project media's thumbnail or a default."""
        return self.thumbnail or 'images/file-default.png'

    def is_video(self):
        return self.mime_type in self.video_mimetypes
示例#2
0
class Challenge(ModelBase):
    """ Inovation (design) Challenges """
    title = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(unique=True)

    title_long = models.CharField(max_length=255)
    brief = models.TextField()
    guidelines = models.TextField()
    important_dates = models.TextField()
    resources = models.TextField()
    rules = models.TextField()

    start_date = models.DateTimeField(default=datetime.now())
    end_date = models.DateTimeField()

    image = models.ImageField(upload_to=determine_image_upload_path,
                              null=True,
                              storage=storage.ImageStorage(),
                              blank=True)

    project = models.ForeignKey(Project)
    created_by = models.ForeignKey('users.UserProfile',
                                   related_name='challenges')
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.now())

    is_open = models.BooleanField()
    allow_voting = models.BooleanField(default=False)

    objects = ChallengeManager()

    def is_active(self):
        return (self.start_date < datetime.now()
                and self.end_date > datetime.now())

    @models.permalink
    def get_absolute_url(self):
        return ('challenges_show', (), {
            'slug': self.slug,
        })

    def __unicode__(self):
        return u"%s (%s - %s)" % (
            self.title, datetime.strftime(self.start_date, "%b %d %Y"),
            datetime.strftime(self.end_date, "%b %d %Y"))

    def save(self):
        """Make sure each challenge has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.title)
            self.slug = slug
            while True:
                existing = Challenge.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = slug + str(count)
                count += 1
        super(Challenge, self).save()
示例#3
0
class School(ModelBase):
    """Placeholder model for schools."""

    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True, blank=True)
    description = models.TextField()
    organizers = models.ManyToManyField('users.UserProfile',
                                        null=True,
                                        blank=True)
    featured = models.ManyToManyField('projects.Project',
                                      related_name='school_featured',
                                      null=True,
                                      blank=True)
    declined = models.ManyToManyField('projects.Project',
                                      related_name='school_declined',
                                      null=True,
                                      blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path,
                              null=True,
                              storage=storage.ImageStorage(),
                              blank=True)
    text_color = models.CharField(max_length=7, default='#5A6579')

    # The term names are used to import school courses from the old site.
    OLD_TERM_NAME_CHOICES = YEAR_IN_SCHOOL_CHOICES = (
        ('Math Future', 'School of the Mathematical Future'),
        ('SoSI', 'School of Social Innovation'),
        ('Webcraft', 'School of Webcraft'),
    )
    old_term_name = models.CharField(max_length=15,
                                     blank=True,
                                     null=True,
                                     choices=OLD_TERM_NAME_CHOICES)

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('school_home', (), {
            'slug': self.slug,
        })

    def save(self):
        """Make sure each school has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = School.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(School, self).save()
示例#4
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = 'http://drumbeat.org/activity/schema/1.0/project'
    generalized_object_type = 'http://activitystrea.ms/schema/1.0/group'

    name = models.CharField(max_length=100, unique=True)
    short_description = models.CharField(max_length=125)
    long_description = models.TextField()

    detailed_description = models.TextField()
    detailed_description_html = models.TextField(null=True, blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path, null=True,
                              storage=storage.ImageStorage(), blank=True)

    slug = models.SlugField(unique=True)
    created_by = models.ForeignKey('users.UserProfile',
                                   related_name='projects')
    featured = models.BooleanField()
    created_on = models.DateTimeField(
        auto_now_add=True, default=datetime.date.today())

    objects = ProjectManager()

    def followers(self):
        """Return a list of users following this project."""
        relationships = Relationship.objects.select_related(
            'source', 'created_by').filter(target_project=self)
        return [rel.source for rel in relationships]

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = slug + str(count)
                count += 1
        super(Project, self).save()
示例#5
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = object_types['group']

    name = models.CharField(max_length=100)

    short_name = models.CharField(max_length=20, null=True, blank=True)

    # Select kind of project (study group, course, or other)
    STUDY_GROUP = 'study group'
    COURSE = 'course'
    CHALLENGE = 'challenge'
    CATEGORY_CHOICES = (
        (STUDY_GROUP, _('Study Group -- group of people working ' \
                        'collaboratively to acquire and share knowledge.')),
        (COURSE, _('Course -- led by one or more organizers with skills on ' \
                   'a field who direct and help participants during their ' \
                   'learning.')),
        (CHALLENGE, _('Challenge -- series of tasks peers can engage in ' \
                      'to develop skills.'))
    )
    category = models.CharField(max_length=30, choices=CATEGORY_CHOICES,
        default=STUDY_GROUP, null=True, blank=False)

    tags = TaggableManager(through=GeneralTaggedItem, blank=True)
    language = models.CharField(max_length=16, choices=settings.LANGUAGES,
        default=settings.LANGUAGE_CODE)

    other = models.CharField(max_length=30, blank=True, null=True)
    other_description = models.CharField(max_length=150, blank=True, null=True)

    short_description = models.CharField(max_length=150)
    long_description = RichTextField(validators=[MaxLengthValidator(700)])

    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)
    duration_hours = models.PositiveIntegerField(default=0, blank=True)
    duration_minutes = models.PositiveIntegerField(default=0, blank=True)

    school = models.ForeignKey('schools.School', related_name='projects',
        null=True, blank=True)

    detailed_description = models.ForeignKey('content.Page',
        related_name='desc_project', null=True, blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path, null=True,
                              storage=storage.ImageStorage(), blank=True)

    slug = models.SlugField(unique=True, max_length=110)

    # this field is deprecated
    featured = models.BooleanField(default=False, verbose_name='staff favourite')

    # this field is deprecated
    community_featured = models.BooleanField(default=False, verbose_name='community pick')

    created_on = models.DateTimeField(
        auto_now_add=True, default=datetime.datetime.now)

    # Indicates a test course. Affects activities and notifications
    test = models.BooleanField(default=False)
    under_development = models.BooleanField(default=True)
    not_listed = models.BooleanField(default=False)
    archived = models.BooleanField(default=False)

    clone_of = models.ForeignKey('projects.Project', blank=True, null=True,
        related_name='derivated_projects')

    imported_from = models.CharField(max_length=150, blank=True, null=True)

    next_projects = models.ManyToManyField('projects.Project',
        symmetrical=False, related_name='previous_projects', blank=True,
        null=True)
    # Stealth Badges awarded upon completion of all tasks.
    completion_badges = models.ManyToManyField('badges.Badge',
        null=True, blank=True, related_name='projects_completion')

    deleted = models.BooleanField(default=False)

    class Meta:
        verbose_name = _('group')

    def __unicode__(self):
        return _('%(name)s %(kind)s') % dict(name=self.name,
            kind=self.kind.lower())

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def friendly_verb(self, verb):
        if verbs['post'] == verb:
            return _('created')

    @property
    def kind(self):
        return self.other.lower() if self.other else self.category

    def followers(self, include_deleted=False):
        relationships = Relationship.objects.all()
        if not include_deleted:
            relationships = relationships.filter(
                source__deleted=False)
        return relationships.filter(target_project=self,
            deleted=False)

    def previous_followers(self, include_deleted=False):
        """Return a list of users who were followers if this project."""
        relationships = Relationship.objects.all()
        if not include_deleted:
            relationships = relationships.filter(
                 source__deleted=False)
        return relationships.filter(target_project=self,
            deleted=True)

    def non_participant_followers(self, include_deleted=False):
        return self.followers(include_deleted).exclude(
            source__id__in=self.participants(include_deleted).values('user_id'))

    def participants(self, include_deleted=False):
        """Return a list of users participating in this project."""
        participations = Participation.objects.all()
        if not include_deleted:
            participations = participations.filter(user__deleted=False)
        return participations.filter(project=self,
            left_on__isnull=True)

    def non_organizer_participants(self, include_deleted=False):
        return self.participants(include_deleted).filter(organizing=False)

    def adopters(self, include_deleted=False):
        return self.participants(include_deleted).filter(Q(adopter=True) | Q(organizing=True))

    def non_adopter_participants(self, include_deleted=False):
        return self.non_organizer_participants(include_deleted).filter(
            adopter=False)

    def organizers(self, include_deleted=False):
        return self.participants(include_deleted).filter(organizing=True)

    def publish(self):
        """ Remove all test, under_development and closed signups from the course """
        self.test = False
        self.under_development = False
        self.save()

        if self.category == self.COURSE:
            signup = self.sign_up.get()
            if signup.is_closed():
                signup.set_unmoderated_signup()

    def is_organizing(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer = self.organizers().filter(user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer or is_superuser
        else:
            return False

    def is_following(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_following = self.followers().filter(source=profile).exists()
            return is_following
        else:
            return False

    def is_participating(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer_or_participant = self.participants().filter(
                user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer_or_participant or is_superuser
        else:
            return False

    def get_metrics_permissions(self, user):
        """Provides metrics related permissions for metrics overview
        and CSV download."""
        if user.is_authenticated():
            if user.is_superuser:
                return True
            if self.is_organizing(user):
                return True
            if not self.school:
                return False
            is_school_organizer = self.school.organizers.filter(
                id=user.id).exists()
            if is_school_organizer:
                return True
        return False

    def get_metric_csv_permission(self, user):
        """Provides metrics related permissions for metrics CSV download."""
        if user.is_authenticated():
            # check for explicit permission grant
            csv_downloaders = settings.STATISTICS_CSV_DOWNLOADERS
            profile = user.get_profile()
            if profile.username in csv_downloaders:
                return True
            return self.get_metrics_permissions(user)
        return False

    def activities(self):
        return Activity.objects.filter(deleted=False,
            scope_object=self).order_by('-created_on')

    def create(self):
        self.save()
        self.send_creation_notification()

    def update_learn_api(self):
        if not self.pk:
            return
        try:
            learn_model.update_course_listing(**self.get_learn_api_data())
        except:
            learn_model.add_course_listing(**self.get_learn_api_data())

        course_url = reverse('projects_show', kwargs={'slug': self.slug})
        course_lists = learn_model.get_lists_for_course(course_url)
        list_names = [ l['name'] for l in course_lists ]
        if self.not_listed or self.test:
            for list_name in list_names:
                learn_model.remove_course_from_list(course_url, list_name)
        else:
            desired_list = 'drafts'
            if not (self.under_development or self.archived):
                desired_list = 'listed'
            elif self.archived:
                desired_list = 'archived'
            possible_lists = ['drafts', 'listed', 'archived']
            possible_lists.remove(desired_list)
            for l in possible_lists:
                if l in list_names:
                    learn_model.remove_course_from_list(course_url, l)
            if desired_list not in list_names:
                learn_model.add_course_to_list(course_url, desired_list)


    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1

        try:
            self.update_learn_api()
        except:
            log.error('Could not update course info in the learn API')
        
        super(Project, self).save()


    def set_duration(self, value):
        """Sets (without saving) duration in hours and minutes given a decimal value.

        e.g., a decimal value of 10.3 equals 10 hours and 18 minutes."""
        value = value or 0
        hours = int(value)
        minutes = int(60 * (value - hours))
        self.duration_hours = hours
        self.duration_minutes = minutes

    def get_duration(self):
        """Gets closest decimal value that represents the current duration.

        e.g., a duration of 10 hours and 18 minutes corresponds to the decimal value 10.3
        """
        return round(self.duration_hours + (self.duration_minutes / 60.0), 1)

    def get_image_url(self):
        missing = settings.STATIC_URL + 'images/project-missing.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def get_learn_api_data(self):
        """ return data used for learn API """
        course_url = reverse('projects_show', kwargs={'slug': self.slug})
        learn_api_data = {
            "course_url": course_url,
            "title": self.name,
            "description": self.short_description,
            "data_url": "",
            "language": self.language,
            "thumbnail_url": self.get_image_url(),
            "tags": self.tags.all().values_list('name', flat=True)
        }
        return learn_api_data

    def send_creation_notification(self):
        """Send notification when a new project is created."""
        subject_template = 'projects/emails/project_created_subject.txt'
        body_template = 'projects/emails/project_created.txt'
        context = {
            'project': self,
            'domain': Site.objects.get_current().domain,
        }
        profiles = [recipient.user for recipient in self.organizers()]
        send_notifications_i18n(profiles, subject_template, body_template,
            context, notification_category='course-created'
        )
        if not self.test:
            admin_subject = render_to_string(
                "projects/emails/admin_project_created_subject.txt",
                context).strip()
            admin_body = render_to_string(
                "projects/emails/admin_project_created.txt", context).strip()
            # TODO send using notifications and get email addresses from group, not settings
            for admin_email in settings.ADMIN_PROJECT_CREATE_EMAIL:
                send_mail(admin_subject, admin_body, admin_email,
                    [admin_email], fail_silently=True)

    def accepted_school(self):
        # Used previously when schools had to decline groups.
        return self.school

    def check_tasks_completion(self, user):
        total_count = self.pages.filter(listed=True,
            deleted=False).count()
        completed_count = PerUserTaskCompletion.objects.filter(
            page__project=self, page__deleted=False,
            unchecked_on__isnull=True, user=user).count()
        if total_count == completed_count:
            for badge in self.completion_badges.all():
                badge.award_to(user)

    def completed_tasks_users(self):
        custom_query = """
SELECT
    `relationships_relationship`.`id`,
    `relationships_relationship`.`source_id`,
    `relationships_relationship`.`target_user_id`,
    `relationships_relationship`.`target_project_id`,
    `relationships_relationship`.`created_on`,
    `relationships_relationship`.`deleted`
FROM
    `relationships_relationship`
INNER JOIN
    `users_userprofile` ON (`relationships_relationship`.`source_id` = `users_userprofile`.`id`)
INNER JOIN
    `projects_perusertaskcompletion` ON  (`relationships_relationship`.`source_id` = `projects_perusertaskcompletion`.`user_id`)
INNER JOIN
    `content_page` U1 ON (`projects_perusertaskcompletion`.`page_id` = U1.`id`)
WHERE
    `projects_perusertaskcompletion`.`unchecked_on` IS NULL
    AND U1.`project_id` = {project_id}
    AND U1.`deleted` = False
    AND `users_userprofile`.`deleted` = False
    AND `relationships_relationship`.`target_project_id` = {project_id}
GROUP BY
    `projects_perusertaskcompletion`.`user_id`, `projects_perusertaskcompletion`.`user_id`
HAVING
    COUNT(`projects_perusertaskcompletion`.`page_id`) = {task_count}
LIMIT 56;"""
        total_count = self.pages.filter(listed=True,
            deleted=False).count()
        #completed_stats = PerUserTaskCompletion.objects.filter(
        #    page__project=self, page__deleted=False,
        #    unchecked_on__isnull=True).values(
        #    'user').annotate(completed_count=Count('page')).filter(
        #    completed_count=total_count)
        #usernames = completed_stats.values_list(
        #    'user', flat=True)
        #return Relationship.objects.filter(source__in=usernames,
        #    target_project=self, source__deleted=False)
        return Relationship.objects.raw(custom_query.format(project_id=self.id, task_count=total_count))

    def get_badges(self):
        from badges.models import Badge
        return Badge.objects.filter(
            Q(groups=self.id) | Q(all_groups=True)).distinct()

    def get_submission_enabled_badges(self):
        from badges.models import Logic
        return self.get_badges().exclude(
            logic__submission_style=Logic.NO_SUBMISSIONS)

    def get_badges_peers_can_give(self):
        from badges.models import Logic, Badge
        return self.get_badges().filter(
            logic__min_votes=1, logic__min_avg_rating=0).exclude(
            logic__submission_style=Logic.SUBMISSION_REQUIRED)

    def get_upon_completion_badges(self, user):
        from badges.models import Badge, Award
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            self_completion_badges = self.completion_badges.all()
            upon_completion_badges = []
            for badge in self_completion_badges:
                missing_prerequisites = badge.prerequisites.exclude(
                    id__in=awarded_badges).exclude(
                    id__in=self_completion_badges.values('id'))
                if not missing_prerequisites.exists():
                    upon_completion_badges.append(badge.id)
            return Badge.objects.filter(id__in=upon_completion_badges)
        else:
            return Badge.objects.none()

    def get_awarded_badges(self, user, exclude_completion_badges=False):
        from badges.models import Badge, Award
        if user.is_authenticated():
            profile = user.get_profile()
            project_badges = self.get_badges()
            if exclude_completion_badges:
                completion_badges = self.completion_badges.all()
                project_badges = project_badges.exclude(
                    id__in=completion_badges.values('id'))
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            return project_badges.filter(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_badges_in_progress(self, user):
        from badges.models import Badge, Award, Submission
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            attempted_badges = Submission.objects.filter(
                author=profile, pending=True).values('badge_id')
            return self.badges.filter(
                id__in=attempted_badges).exclude(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_non_attempted_badges(self, user):
        from badges.models import Badge, Award, Submission
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            attempted_badges = Submission.objects.filter(
                author=profile).values('badge_id')
            project_badges = self.get_submission_enabled_badges()
            # Excluding both awarded and attempted badges
            # In case honorary award do not rely on submissions.
            return project_badges.exclude(
                id__in=attempted_badges).exclude(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_non_started_next_projects(self, user):
        """To be displayed in the Join Next Challenges section."""
        if user.is_authenticated():
            profile = user.get_profile()
            joined = Participation.objects.filter(
                user=profile).values('project_id')
            return self.next_projects.exclude(
                id__in=joined)
        else:
            return Project.objects.none()
   
    @staticmethod
    def filter_activities(activities):
        from statuses.models import Status
        content_types = [
            ContentType.objects.get_for_model(Page),
            ContentType.objects.get_for_model(PageComment),
            ContentType.objects.get_for_model(Status),
            ContentType.objects.get_for_model(Project),
        ]
        return activities.filter(target_content_type__in=content_types)

    @staticmethod
    def filter_learning_activities(activities):
        pages_ct = ContentType.objects.get_for_model(Page)
        comments_ct = ContentType.objects.get_for_model(PageComment)
        return activities.filter(
            target_content_type__in=[pages_ct, comments_ct])
示例#6
0
文件: models.py 项目: mkcode/lernanta
class UserProfile(ModelBase):
    """Each user gets a profile."""
    object_type = object_types['person']

    username = models.CharField(max_length=255, default='', unique=True)
    full_name = models.CharField(max_length=255,
                                 default='',
                                 null=True,
                                 blank=True)
    password = models.CharField(max_length=255, default='')
    email = models.EmailField(unique=True, null=True)
    bio = RichTextField(blank=True)
    image = models.ImageField(upload_to=determine_upload_path,
                              default='',
                              blank=True,
                              null=True,
                              storage=storage.ImageStorage())
    confirmation_code = models.CharField(max_length=255,
                                         default='',
                                         blank=True)
    location = models.CharField(max_length=255, blank=True, default='')
    featured = models.BooleanField()
    newsletter = models.BooleanField()
    discard_welcome = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)
    preflang = models.CharField(verbose_name='preferred language',
                                max_length=16,
                                choices=settings.SUPPORTED_LANGUAGES,
                                default=settings.LANGUAGE_CODE)
    deleted = models.BooleanField(default=False)
    last_active = models.DateTimeField(null=True, blank=True)

    user = models.ForeignKey(User, null=True, editable=False, blank=True)

    tags = CategoryTaggableManager(through=TaggedProfile, blank=True)

    objects = UserProfileManager()

    def __unicode__(self):
        if self.deleted:
            return ugettext('Anonym')
        return self.full_name or self.username

    def following(self, model=None):
        """
        Return a list of objects this user is following. All objects returned
        will be ```Project``` or ```UserProfile``` instances. Optionally filter
        by type by including a ```model``` parameter.
        """
        if (model == 'Project' or isinstance(model, Project)
                or model == Project):
            relationships = Relationship.objects.select_related(
                'target_project').filter(
                    source=self,
                    deleted=False).exclude(target_project__isnull=True)
            return [
                rel.target_project for rel in relationships
                if not rel.target_project.archived
            ]
        relationships = Relationship.objects.select_related(
            'target_user').filter(
                source=self, target_user__deleted=False,
                deleted=False).exclude(target_user__isnull=True)
        return [rel.target_user for rel in relationships]

    def followers(self):
        """Return a list of this users followers."""
        relationships = Relationship.objects.select_related('source').filter(
            target_user=self, source__deleted=False, deleted=False)
        return [rel.source for rel in relationships]

    def is_following(self, model):
        """Determine whether this user is following ```model```."""
        return model in self.following(model=model)

    def get_current_projects(self, only_public=False):
        projects = self.following(model=Project)
        projects_organizing = []
        projects_participating = []
        projects_following = []
        count = len(projects)
        for project in projects:
            if only_public and project.not_listed:
                count -= 1
                continue
            is_challenge = (project.category == Project.CHALLENGE)
            if is_challenge:
                organizers = project.adopters()
                participants = project.non_adopter_participants()
            else:
                organizers = project.organizers()
                participants = project.non_organizer_participants()
            if organizers.filter(user=self).exists():
                if is_challenge:
                    project.relation_text = _('(adopted)')
                else:
                    project.relation_text = _('(organizing)')
                projects_organizing.append(project)
            elif participants.filter(user=self).exists():
                project.relation_text = _('(participating)')
                projects_participating.append(project)
            elif not is_challenge:
                project.relation_text = _('(following)')
                projects_following.append(project)
        data = {
            'organizing': projects_organizing,
            'participating': projects_participating,
            'following': projects_following,
            'count': count,
        }
        return data

    def get_past_projects(self, only_public=False):
        participations = Participation.objects.filter(user=self)
        current = participations.filter(project__archived=False,
                                        left_on__isnull=True)
        participations = participations.exclude(
            project__id__in=current.values('project_id'))
        past_projects = {}
        for p in participations:
            if p.project.slug in past_projects:
                past_projects[p.project.slug]['organizer'] |= p.organizing
            elif not only_public or not p.project.not_listed:
                past_projects[p.project.slug] = {
                    'name': p.project.name,
                    'url': p.project.get_absolute_url(),
                    'organizer': p.organizing,
                    'image_url': p.project.get_image_url(),
                }
        return past_projects.values()

    @models.permalink
    def get_absolute_url(self):
        username = '******' if self.deleted else self.username
        return ('users_profile_view', (), {
            'username': username,
        })

    def email_confirmation_code(self, url, new_user=True):
        """Send a confirmation email to the user after registering."""
        subject_template = 'users/emails/registration_confirm_subject.txt'
        body_template = 'users/emails/registration_confirm.txt'
        context = {'confirmation_url': url, 'new_user': new_user}
        send_notifications([self], subject_template, body_template, context)

    def image_or_default(self):
        """Return user profile image or a default."""
        avatar = '%s%s' % (settings.STATIC_URL, '/images/member-missing.png')
        if not self.deleted:
            gravatarUrl = self.gravatar(240)
            if self.image:
                avatar = '%s%s' % (settings.MEDIA_URL, self.image)
            elif gravatarUrl:
                avatar = gravatarUrl
        return mark_safe(avatar)

    def gravatar(self, size=240):
        hash = hashlib.md5(self.email.lower()).hexdigest()
        default = urlquote_plus(settings.DEFAULT_PROFILE_IMAGE)
        return GRAVATAR_TEMPLATE % {
            'size': size,
            'gravatar_hash': hash,
            'default': default,
            'rating': "g",
            'username': self.username,
        }

    def generate_confirmation_code(self):
        if not self.confirmation_code:
            self.confirmation_code = ''.join(
                random.sample(string.letters + string.digits, 60))
        return self.confirmation_code

    def set_password(self, raw_password, algorithm='sha512'):
        self.password = create_password(algorithm, raw_password)

    def check_password(self, raw_password):
        if '$' not in self.password:
            valid = (get_hexdigest('md5', '', raw_password) == self.password)
            if valid:
                # Upgrade an old password.
                self.set_password(raw_password)
                self.save()
            return valid

        algo, salt, hsh = self.password.split('$')
        return hsh == get_hexdigest(algo, salt, raw_password)

    def can_post(self):
        return len(self.confirmation_code) == 0 and self.deleted == False
示例#7
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = 'http://drumbeat.org/activity/schema/1.0/project'
    generalized_object_type = 'http://activitystrea.ms/schema/1.0/group'

    name = models.CharField(max_length=100)
    short_description = models.CharField(max_length=125)
    long_description = models.TextField(validators=[MaxLengthValidator(700)])

    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

    school = models.ForeignKey('schools.School',
                               related_name='projects',
                               null=True,
                               blank=True)

    detailed_description = models.ForeignKey('content.Page',
                                             related_name='desc_project',
                                             null=True,
                                             blank=True)
    sign_up = models.ForeignKey('content.Page',
                                related_name='sign_up_project',
                                null=True,
                                blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path,
                              null=True,
                              storage=storage.ImageStorage(),
                              blank=True)

    slug = models.SlugField(unique=True, max_length=110)
    created_by = models.ForeignKey('users.UserProfile',
                                   related_name='projects')
    featured = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)

    under_development = models.BooleanField(default=True)
    testing_sandbox = models.BooleanField(default=False)
    signup_closed = models.BooleanField(default=True)

    objects = ProjectManager()

    class Meta:
        verbose_name = _('study group')

    def followers(self):
        """Return a list of users following this project."""
        relationships = Relationship.objects.select_related(
            'source', 'created_by').filter(target_project=self)
        return [rel.source for rel in relationships]

    def non_participant_followers(self):
        from users.models import UserProfile
        followers_ids = Relationship.objects.select_related(
            'source',
            'created_by').filter(target_project=self).values('source_id')
        followers = UserProfile.objects.filter(id__in=followers_ids)
        non_participants = followers.exclude(pk=self.created_by.pk)
        non_participants = non_participants.exclude(
            id__in=self.participants().values('user_id'))
        return non_participants

    def participants(self):
        """Return a list of users participating in this project."""
        return Participation.objects.filter(project=self, left_on__isnull=True)

    def activities(self):
        activities = Activity.objects.filter(
            Q(project=self) | Q(target_project=self), ).exclude(
                verb='http://activitystrea.ms/schema/1.0/follow').order_by(
                    '-created_on')
        return activities

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Project, self).save()
示例#8
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = object_types['group']

    name = models.CharField(max_length=100)
    kind = models.CharField(max_length=30, default=_('Study Group'))
    short_description = models.CharField(max_length=150)
    long_description = models.TextField(validators=[MaxLengthValidator(700)])

    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

    school = models.ForeignKey('schools.School',
                               related_name='projects',
                               null=True,
                               blank=True)

    detailed_description = models.ForeignKey('content.Page',
                                             related_name='desc_project',
                                             null=True,
                                             blank=True)
    sign_up = models.ForeignKey('content.Page',
                                related_name='sign_up_project',
                                null=True,
                                blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path,
                              null=True,
                              storage=storage.ImageStorage(),
                              blank=True)

    slug = models.SlugField(unique=True, max_length=110)
    featured = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)

    under_development = models.BooleanField(default=True)
    not_listed = models.BooleanField(default=False)
    signup_closed = models.BooleanField(default=True)
    archived = models.BooleanField(default=False)

    clone_of = models.ForeignKey('projects.Project',
                                 blank=True,
                                 null=True,
                                 related_name='derivated_projects')

    imported_from = models.CharField(max_length=150, blank=True, null=True)

    objects = ProjectManager()

    class Meta:
        verbose_name = _('group')

    def __unicode__(self):
        return _('%(name)s %(kind)s') % dict(name=self.name,
                                             kind=self.kind.lower())

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def friendly_verb(self, verb):
        if verbs['post'] == verb:
            return _('created')

    def followers(self):
        return Relationship.objects.filter(deleted=False,
                                           target_project=self,
                                           source__deleted=False)

    def non_participant_followers(self):
        return self.followers().exclude(
            source__id__in=self.participants().values('user_id'))

    def participants(self):
        """Return a list of users participating in this project."""
        return Participation.objects.filter(project=self,
                                            left_on__isnull=True,
                                            user__deleted=False)

    def pending_applicants(self):
        page = self.sign_up
        users = []
        first_level_comments = page.comments.filter(reply_to__isnull=True)
        for answer in first_level_comments.filter(deleted=False):
            is_participant = self.participants().filter(
                user=answer.author).exists()
            if not is_participant and not answer.author.deleted:
                users.append(answer.author)
        return users

    def non_organizer_participants(self):
        return self.participants().filter(organizing=False)

    def organizers(self):
        return self.participants().filter(organizing=True)

    def is_organizing(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer = self.organizers().filter(user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer or is_superuser
        else:
            return False

    def is_following(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_following = self.followers().filter(source=profile).exists()
            return is_following
        else:
            return False

    def is_participating(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer_or_participant = self.participants().filter(
                user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer_or_participant or is_superuser
        else:
            return False

    def is_pending_signup(self, user):
        for applicant in self.pending_applicants():
            if applicant == user:
                return True
        return False

    def activities(self):
        return Activity.objects.filter(
            deleted=False, scope_object=self).order_by('-created_on')

    def create(self):
        self.save()
        self.send_creation_notification()

    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Project, self).save()

    def get_image_url(self):
        missing = settings.MEDIA_URL + 'images/project-missing.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def send_creation_notification(self):
        """Send notification when a new project is created."""
        project = self
        ulang = get_language()
        subject = {}
        body = {}
        domain = Site.objects.get_current().domain
        for l in settings.SUPPORTED_LANGUAGES:
            activate(l[0])
            subject[l[0]] = render_to_string(
                "projects/emails/project_created_subject.txt", {
                    'project': project,
                }).strip()
            body[l[0]] = render_to_string(
                "projects/emails/project_created.txt", {
                    'project': project,
                    'domain': domain,
                }).strip()
        activate(ulang)
        for organizer in project.organizers():
            if not organizer.no_updates:
                ol = organizer.user.preflang or settings.LANGUAGE_CODE
                SendUserEmail.apply_async(
                    (organizer.user, subject[ol], body[ol]))
        admin_subject = render_to_string(
            "projects/emails/admin_project_created_subject.txt", {
                'project': project,
            }).strip()
        admin_body = render_to_string(
            "projects/emails/admin_project_created.txt", {
                'project': project,
                'domain': domain,
            }).strip()
        for admin_email in settings.ADMIN_PROJECT_CREATE_EMAIL:
            send_mail(admin_subject,
                      admin_body,
                      admin_email, [admin_email],
                      fail_silently=True)

    def accepted_school(self):
        school = self.school
        if school and school.declined.filter(id=self.id).exists():
            school = None
        return school
示例#9
0
文件: models.py 项目: mkcode/lernanta
class School(ModelBase):
    """Placeholder model for schools."""

    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True, blank=True)
    short_name = models.CharField(max_length=20)
    description = RichTextField(config_name='rich')
    more_info = RichTextField(config_name='rich', null=True, blank=True)
    organizers = models.ManyToManyField('users.UserProfile',
                                        null=True,
                                        blank=True)
    featured = models.ManyToManyField('projects.Project',
                                      related_name='school_featured',
                                      null=True,
                                      blank=True)

    logo = models.ImageField(upload_to=schools_determine_image_upload_path,
                             null=True,
                             storage=storage.ImageStorage(),
                             blank=True)
    groups_icon = models.ImageField(
        upload_to=schools_determine_image_upload_path,
        null=True,
        storage=storage.ImageStorage(),
        blank=True)
    background = models.ImageField(
        upload_to=schools_determine_image_upload_path,
        null=True,
        storage=storage.ImageStorage(),
        blank=True)
    site_logo = models.ImageField(
        upload_to=schools_determine_image_upload_path,
        null=True,
        storage=storage.ImageStorage(),
        blank=True)

    headers_color = models.CharField(max_length=7, default='#5a6579')
    headers_color_light = models.CharField(max_length=7, default='#f08c00')
    background_color = models.CharField(max_length=7, default='#ffffff')
    menu_color = models.CharField(max_length=7, default='#36cdc4')
    menu_color_light = models.CharField(max_length=7, default='#4bd2c9')

    sidebar_width = models.CharField(max_length=5, default='245px')
    show_school_organizers = models.BooleanField(default=True)

    extra_styles = models.TextField(blank=True)

    # The term names are used to import school courses from the old site.
    OLD_TERM_NAME_CHOICES = YEAR_IN_SCHOOL_CHOICES = (
        ('Math Future', 'School of the Mathematical Future'),
        ('SoSI', 'School of Social Innovation'),
        ('Webcraft', 'School of Webcraft'),
    )
    old_term_name = models.CharField(max_length=15,
                                     blank=True,
                                     null=True,
                                     choices=OLD_TERM_NAME_CHOICES)

    mentor_form_url = models.URLField(blank=True, null=True)
    mentee_form_url = models.URLField(blank=True, null=True)

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('school_home', (), {
            'slug': self.slug,
        })

    def save(self):
        """Make sure each school has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = School.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(School, self).save()
示例#10
0
class Badge(models.Model):
    """Representation of a Badge"""
    name = models.CharField(max_length=225, blank=False)
    slug = models.SlugField(unique=True, max_length=110)
    description = models.CharField(max_length=225, blank=False)
    image = models.ImageField(
        upload_to=determine_upload_path, default='', blank=True, null=True,
        storage=storage.ImageStorage())
    prerequisites = models.ManyToManyField('self', symmetrical=False,
        blank=True, null=True)
    unique = models.BooleanField(
        help_text=_('If can only be awarded to the user once.'),
        default=False)
    SELF = 'self'
    PEER = 'peer'
    STEALTH = 'stealth'

    ASSESSMENT_TYPE_CHOICES = (
        (SELF, _('Self assessment -- able to get the badge without ' \
                        'outside assessment')),
        (PEER, _('Peer assessment -- community or skill badges users ' \
                        'grant each other')),
        (STEALTH, _('Stealth assessment -- badges granted by the system '\
                        'based on supplied logic. Accumulative.'))
    )

    assessment_type = models.CharField(max_length=30,
        choices=ASSESSMENT_TYPE_CHOICES,
        default=SELF, null=True, blank=False)

    COMPLETION = 'completion/aggregate'
    SKILL = 'skill'
    COMMUNITY = 'peer-to-peer/community'
    STEALTH = 'stealth'
    OTHER = 'other'

    BADGE_TYPE_CHOICES = (
        (COMPLETION, _('Completion/aggregate badge -- awarded by self '\
            'assessments')),
        (SKILL, _('Skill badge -- badges that are skill based and assessed '\
            'by peers with related logic')),
        (COMMUNITY, _('Peer-to-peer/community badge -- badges granted by '\
            'peers')),
        (STEALTH, _('Stealth badge -- system awarded badges')),
        (OTHER, _('Other badges -- badges like course organizer or those '\
            'staff issued'))
    )

    badge_type = models.CharField(max_length=30, choices=BADGE_TYPE_CHOICES,
        default=COMPLETION, null=True, blank=False)

    rubrics = models.ManyToManyField('badges.Rubric', related_name='badges',
        null=True, blank=True)
    logic = models.ForeignKey('badges.Logic', related_name='badges',
        null=True, blank=True,
        help_text=_('If no logic is chosen, no logic required. '\
        ' Example: self-assessment badges.'))

    groups = models.ManyToManyField('projects.Project', related_name='badges',
        null=True, blank=True)

    creator = models.ForeignKey('users.UserProfile', related_name='badges',
        blank=True, null=True)
    created_on = models.DateTimeField(auto_now_add=True, blank=False)
    last_update = models.DateTimeField(auto_now_add=True, blank=False)

    def __unicode__(self):
        return "%s %s" % (self.name, _('Badge'))

    @models.permalink
    def get_absolute_url(self):
        return ('badges_show', (), {
            'slug': self.slug,
        })

    def get_image_url(self):
        # TODO: using project's default image until a default badge
        # image is added.
        missing = settings.MEDIA_URL + 'images/missing-badge.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def save(self):
        """Make sure each badge has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Badge.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Badge, self).save()

    def is_eligible(self, user):
        """Check if the user eligible for the badge.

        If some prerequisite badges have not been
        awarded returns False."""
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            return not self.prerequisites.exclude(
                id__in=awarded_badges).exists()
        else:
            return False

    def is_awarded_to(self, user):
        """Does the user have the badge?"""
        return Award.objects.filter(user=user, badge=self).count() > 0

    def award_to(self, user):
        """Award the badge to the user.

        Returns None if no badge is awarded."""
        if not self.is_eligible(user.user):
            # If the user is not eligible the badge
            # is not awarded.
            return None

        # If logic restrictions are not meet the badge is not awarded.
        if self.logic and not self.logic.is_eligible(self, user):
            return None

        if self.unique:
            # Do not award the badge if the user can not have the badge
            # more than once and it was already awarded.
            award, created = Award.objects.get_or_create(user=user,
                badge=self)
            return award if created else None

        return Award.objects.create(user=user, badge=self)

    def get_pending_submissions(self):
        """Submissions of users who haven't received the award yet"""
        all_submissions = Submission.objects.filter(badge=self)
        pending_submissions = []
        for submission in all_submissions:
            if not self.is_awarded_to(submission.author):
                pending_submissions.append(submission)
        return pending_submissions

    def progress_for(self, user):
        """Progress for a user for this badge"""
        progress = Progress.objects.filter(user=user, badge=self)
        if progress:
            progress = progress[0]
        else:
            progress = Progress(user=user, badge=self)
        return progress

    def get_peers(self, profile):
        from projects.models import Participation
        from users.models import UserProfile
        badge_projects = self.groups.values('id')
        user_projects = Participation.objects.filter(
            user=profile).values('project__id')
        peers = Participation.objects.filter(
            project__in=badge_projects).filter(
            project__in=user_projects).values('user__id')
        return UserProfile.objects.filter(deleted=False,
            id__in=peers).exclude(id=profile.id)

    def other_badges_can_apply_for(self):
        badges = Badge.objects.exclude(
            id=self.id).filter(badge_type=Badge.SKILL).filter(
            assessment_type=Badge.PEER)
        badge_groups = self.groups.values('id')
        related_badges = badges.filter(
            groups__in=badge_groups).distinct()
        non_related_badges = badges.exclude(
            groups__in=badge_groups).distinct()
        return MultiQuerySet(related_badges, non_related_badges)
示例#11
0
class UserProfile(ModelBase):
    """Each user gets a profile."""
    object_type = 'http://activitystrea.ms/schema/1.0/person'

    username = models.CharField(max_length=255, default='', unique=True)
    display_name = models.CharField(max_length=255,
                                    default='',
                                    null=True,
                                    blank=True)
    password = models.CharField(max_length=255, default='')
    email = models.EmailField(unique=True, null=True)
    bio = models.TextField(blank=True, default='')
    image = models.ImageField(upload_to=determine_upload_path,
                              default='',
                              blank=True,
                              null=True,
                              storage=storage.ImageStorage())
    confirmation_code = models.CharField(max_length=255,
                                         default='',
                                         blank=True)
    location = models.CharField(max_length=255, blank=True, default='')
    featured = models.BooleanField()
    newsletter = models.BooleanField()
    discard_welcome = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.date.today())

    user = models.ForeignKey(User, null=True, editable=False, blank=True)
    tags = TaggableManager(through=TaggedProfile)

    objects = UserProfileManager()

    def __unicode__(self):
        return self.display_name or self.username

    def following(self, model=None):
        """
        Return a list of objects this user is following. All objects returned
        will be ```Project``` or ```UserProfile``` instances. Optionally filter
        by type by including a ```model``` parameter.
        """
        if isinstance(model, Project) or model == Project:
            relationships = Relationship.objects.select_related(
                'target_project').filter(source=self).exclude(
                    target_project__isnull=True)
            return [rel.target_project for rel in relationships]
        relationships = Relationship.objects.select_related(
            'target_user').filter(source=self).exclude(
                target_user__isnull=True)
        return [rel.target_user for rel in relationships]

    def followers(self):
        """Return a list of this users followers."""
        relationships = Relationship.objects.select_related('source').filter(
            target_user=self)
        return [rel.source for rel in relationships]

    def is_following(self, model):
        """Determine whether this user is following ```model```."""
        return model in self.following(model=model)

    @models.permalink
    def get_absolute_url(self):
        return ('users_profile_view', (), {
            'username': self.username,
        })

    def create_django_user(self):
        """Make a django.contrib.auth.models.User for this UserProfile."""
        self.user = User(id=self.pk)
        self.user.username = self.username
        self.user.email = self.email
        self.user.date_joined = self.created_on
        self.user.backend = 'django.contrib.auth.backends.ModelBackend'
        self.user.save()
        self.save()
        return self.user

    def email_confirmation_code(self, url):
        """Send a confirmation email to the user after registering."""
        body = render_to_string('users/emails/registration_confirm.txt', {
            'confirmation_url': url,
        })
        subject = _('Complete Registration')
        tasks.SendUserEmail.apply_async(args=(self, subject, body))

    def image_or_default(self):
        """Return user profile image or a default."""
        return self.image or 'images/member-missing.png'

    def generate_confirmation_code(self):
        if not self.confirmation_code:
            self.confirmation_code = ''.join(
                random.sample(string.letters + string.digits, 60))
        return self.confirmation_code

    def set_password(self, raw_password, algorithm='sha512'):
        self.password = create_password(algorithm, raw_password)

    def check_password(self, raw_password):
        if '$' not in self.password:
            valid = (get_hexdigest('md5', '', raw_password) == self.password)
            if valid:
                # Upgrade an old password.
                self.set_password(raw_password)
                self.save()
            return valid

        algo, salt, hsh = self.password.split('$')
        return hsh == get_hexdigest(algo, salt, raw_password)

    @property
    def name(self):
        return self.display_name or self.username
示例#12
0
文件: models.py 项目: mkcode/lernanta
class ProjectSet(ModelBase):
    "Model for the project sets"
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True, blank=True)
    description = RichTextField(config_name='rich')
    short_description = models.CharField(max_length=150)
    school = models.ForeignKey(School,
                               blank=True,
                               null=True,
                               related_name="project_sets")
    projects = models.ManyToManyField('projects.Project',
                                      blank=True,
                                      null=True,
                                      related_name="projectsets",
                                      through='schools.ProjectSetIndex')
    featured = models.BooleanField(default=False)
    image = models.ImageField(
        upload_to=projectsets_determine_image_upload_path,
        null=True,
        storage=storage.ImageStorage(),
        blank=True)

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('school_projectset', (), {
            'slug': self.school.slug,
            'set_slug': self.slug,
        })

    def get_image_url(self):
        # TODO: using project's default image until a default badge
        # image is added.
        missing = settings.STATIC_URL + 'images/missing-challenge-set.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def get_projects(self):
        return self.projects.order_by('projectsetindex__index')

    @property
    def first_project(self):
        try:
            return self.projects.order_by('projectsetindex__index')[0]
        except IndexError:
            return None

    def _distinct_participants(self):
        return UserProfile.objects.filter(
            participations__project__projectsets=self,
            deleted=False,
            participations__left_on__isnull=True).distinct()

    def total_participants(self):
        return self._distinct_participants().filter(
            participations__adopter=False,
            participations__organizing=False).count()

    def total_adopters(self):
        return self._distinct_participants().filter(
            Q(participations__adopter=True)
            | Q(participations__organizing=True)).count()

    def total_badges(self):
        return Badge.objects.filter(
            groups__projectsets=self).distinct().count()
示例#13
0
class UserProfile(ModelBase):
    """Each user gets a profile."""
    object_type = 'http://activitystrea.ms/schema/1.0/person'

    username = models.CharField(max_length=255, default='', unique=True)
    full_name = models.CharField(max_length=255,
                                 default='',
                                 null=True,
                                 blank=True)
    password = models.CharField(max_length=255, default='')
    email = models.EmailField(unique=True, null=True)
    bio = models.TextField(blank=True, default='')
    image = models.ImageField(upload_to=determine_upload_path,
                              default='',
                              blank=True,
                              null=True,
                              storage=storage.ImageStorage())
    confirmation_code = models.CharField(max_length=255,
                                         default='',
                                         blank=True)
    location = models.CharField(max_length=255, blank=True, default='')
    featured = models.BooleanField()
    newsletter = models.BooleanField()
    discard_welcome = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)

    user = models.ForeignKey(User, null=True, editable=False, blank=True)
    tags = TaggableManager(through=TaggedProfile)

    objects = UserProfileManager()

    def __unicode__(self):
        return self.full_name or self.username

    def following(self, model=None):
        """
        Return a list of objects this user is following. All objects returned
        will be ```Project``` or ```UserProfile``` instances. Optionally filter
        by type by including a ```model``` parameter.
        """
        if (model == 'Project' or isinstance(model, Project)
                or model == Project):
            relationships = Relationship.objects.select_related(
                'target_project').filter(source=self).exclude(
                    target_project__isnull=True)
            return [rel.target_project for rel in relationships]
        relationships = Relationship.objects.select_related(
            'target_user').filter(source=self).exclude(
                target_user__isnull=True)
        return [rel.target_user for rel in relationships]

    def followers(self):
        """Return a list of this users followers."""
        relationships = Relationship.objects.select_related('source').filter(
            target_user=self)
        return [rel.source for rel in relationships]

    def is_following(self, model):
        """Determine whether this user is following ```model```."""
        return model in self.following(model=model)

    @models.permalink
    def get_absolute_url(self):
        return ('users_profile_view', (), {
            'username': self.username,
        })

    def email_confirmation_code(self, url):
        """Send a confirmation email to the user after registering."""
        body = render_to_string('users/emails/registration_confirm.txt', {
            'confirmation_url': url,
        })
        subject = ugettext('Complete Registration')
        tasks.SendUserEmail.apply_async(args=(self, subject, body))

    def image_or_default(self):
        """Return user profile image or a default."""
        gravatarUrl = self.gravatar(54)
        avatar = '%s%s' % (settings.MEDIA_URL, '/images/member-missing.png')
        if self.image:
            avatar = '%s%s' % (settings.MEDIA_URL, self.image)
        elif gravatarUrl:
            avatar = gravatarUrl
        return mark_safe(avatar)

    def gravatar(self, size=54):
        hash = hashlib.md5(self.email.lower()).hexdigest()
        default = urlquote_plus(settings.DEFAULT_PROFILE_IMAGE)
        return GRAVATAR_TEMPLATE % {
            'size': size,
            'gravatar_hash': hash,
            'default': default,
            'rating': "g",
            'username': self.username,
        }

    def generate_confirmation_code(self):
        if not self.confirmation_code:
            self.confirmation_code = ''.join(
                random.sample(string.letters + string.digits, 60))
        return self.confirmation_code

    def set_password(self, raw_password, algorithm='sha512'):
        self.password = create_password(algorithm, raw_password)

    def check_password(self, raw_password):
        if '$' not in self.password:
            valid = (get_hexdigest('md5', '', raw_password) == self.password)
            if valid:
                # Upgrade an old password.
                self.set_password(raw_password)
                self.save()
            return valid

        algo, salt, hsh = self.password.split('$')
        return hsh == get_hexdigest(algo, salt, raw_password)

    @property
    def display_name(self):
        return self.full_name or self.username
示例#14
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = object_types['group']

    name = models.CharField(max_length=100)

    # Select kind of project (study group, course, or other)
    STUDY_GROUP = 'study group'
    COURSE = 'course'
    CHALLENGE = 'challenge'
    CATEGORY_CHOICES = (
        (STUDY_GROUP, _('Study Group -- group of people working ' \
                        'collaboratively to acquire and share knowledge.')),
        (COURSE, _('Course -- led by one or more organizers with skills on ' \
                   'a field who direct and help participants during their ' \
                   'learning.')),
        (CHALLENGE, _('Challenge -- series of tasks peers can engage in ' \
                      'to develop skills.'))
    )
    category = models.CharField(max_length=30, choices=CATEGORY_CHOICES,
        default=STUDY_GROUP, null=True, blank=False)

    tags = TaggableManager(through=GeneralTaggedItem, blank=True)

    other = models.CharField(max_length=30, blank=True, null=True)
    other_description = models.CharField(max_length=150, blank=True, null=True)

    short_description = models.CharField(max_length=150)
    long_description = RichTextField(validators=[MaxLengthValidator(700)])

    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

    school = models.ForeignKey('schools.School', related_name='projects',
        null=True, blank=True)

    detailed_description = models.ForeignKey('content.Page',
        related_name='desc_project', null=True, blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path, null=True,
                              storage=storage.ImageStorage(), blank=True)

    slug = models.SlugField(unique=True, max_length=110)
    featured = models.BooleanField(default=False)
    created_on = models.DateTimeField(
        auto_now_add=True, default=datetime.datetime.now)

    under_development = models.BooleanField(default=True)
    not_listed = models.BooleanField(default=False)
    archived = models.BooleanField(default=False)

    clone_of = models.ForeignKey('projects.Project', blank=True, null=True,
        related_name='derivated_projects')

    imported_from = models.CharField(max_length=150, blank=True, null=True)

    next_projects = models.ManyToManyField('projects.Project',
        symmetrical=False, related_name='previous_projects', blank=True,
        null=True)

    objects = ProjectManager()

    class Meta:
        verbose_name = _('group')

    def __unicode__(self):
        return _('%(name)s %(kind)s') % dict(name=self.name,
            kind=self.kind.lower())

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def friendly_verb(self, verb):
        if verbs['post'] == verb:
            return _('created')

    @property
    def kind(self):
        return self.other.lower() if self.other else self.category

    def followers(self, include_deleted=False):
        relationships = Relationship.objects.all()
        if not include_deleted:
            relationships = relationships.filter(
                source__deleted=False)
        return relationships.filter(target_project=self,
            deleted=False)

    def previous_followers(self, include_deleted=False):
        """Return a list of users who were followers if this project."""
        relationships = Relationship.objects.all()
        if not include_deleted:
            relationships = relationships.filter(
                 source__deleted=False)
        return relationships.filter(target_project=self,
            deleted=True)

    def non_participant_followers(self, include_deleted=False):
        return self.followers(include_deleted).exclude(
            source__id__in=self.participants(include_deleted).values('user_id'))

    def participants(self, include_deleted=False):
        """Return a list of users participating in this project."""
        participations = Participation.objects.all()
        if not include_deleted:
            participations = participations.filter(user__deleted=False)
        return participations.filter(project=self,
            left_on__isnull=True)

    def non_organizer_participants(self, include_deleted=False):
        return self.participants(include_deleted).filter(organizing=False)

    def adopters(self, include_deleted=False):
        return self.participants(include_deleted).filter(Q(adopter=True) | Q(organizing=True))

    def non_adopter_participants(self, include_deleted=False):
        return self.non_organizer_participants(include_deleted).filter(
            adopter=False)

    def organizers(self, include_deleted=False):
        return self.participants(include_deleted).filter(organizing=True)

    def is_organizing(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer = self.organizers().filter(user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer or is_superuser
        else:
            return False

    def is_following(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_following = self.followers().filter(source=profile).exists()
            return is_following
        else:
            return False

    def is_participating(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer_or_participant = self.participants().filter(
                user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer_or_participant or is_superuser
        else:
            return False

    def get_metrics_permissions(self, user):
        """Provides metrics related permissions for metrics overview
        and csv download."""
        if user.is_authenticated():
            if user.is_superuser:
                return True, True
            allowed_schools = settings.STATISTICS_ENABLED_SCHOOLS
            if not self.school or self.school.slug not in allowed_schools:
                return False, False
            csv_downloaders = settings.STATISTICS_CSV_DOWNLOADERS
            profile = user.get_profile()
            csv_permission = profile.username in csv_downloaders
            is_school_organizer = self.school.organizers.filter(
                id=user.id).exists()
            if is_school_organizer or self.is_organizing(user):
                return True, csv_permission
        return False, False

    def activities(self):
        return Activity.objects.filter(deleted=False,
            scope_object=self).order_by('-created_on')

    def create(self):
        self.save()
        self.send_creation_notification()

    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Project, self).save()

    def get_image_url(self):
        missing = settings.MEDIA_URL + 'images/project-missing.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def send_creation_notification(self):
        """Send notification when a new project is created."""
        context = {
            'project': self,
            'domain': Site.objects.get_current().domain,
        }
        subjects, bodies = localize_email(
            'projects/emails/project_created_subject.txt',
            'projects/emails/project_created.txt', context)
        for organizer in self.organizers():
            SendUserEmail.apply_async((organizer.user, subjects, bodies))
        admin_subject = render_to_string(
            "projects/emails/admin_project_created_subject.txt",
            context).strip()
        admin_body = render_to_string(
            "projects/emails/admin_project_created.txt", context).strip()
        for admin_email in settings.ADMIN_PROJECT_CREATE_EMAIL:
            send_mail(admin_subject, admin_body, admin_email,
                [admin_email], fail_silently=True)

    def accepted_school(self):
        # Used previously when schools had to decline groups.
        return self.school

    def check_tasks_completion(self, user):
        total_count = self.pages.filter(listed=True,
            deleted=False).count()
        completed_count = PerUserTaskCompletion.objects.filter(
            page__project=self, page__deleted=False,
            unchecked_on__isnull=True, user=user).count()
        if total_count == completed_count:
            badges = self.get_project_badges(only_self_completion=True)
            for badge in badges:
                badge.award_to(user)

    def completed_tasks_users(self):
        total_count = self.pages.filter(listed=True,
            deleted=False).count()
        completed_stats = PerUserTaskCompletion.objects.filter(
            page__project=self, page__deleted=False,
            unchecked_on__isnull=True).values(
            'user__username').annotate(completed_count=Count('page')).filter(
            completed_count=total_count)
        usernames = completed_stats.values(
            'user__username')
        return Relationship.objects.filter(source__username__in=usernames,
            target_project=self, source__deleted=False)

    def get_project_badges(self, only_self_completion=False,
            only_peer_skill=False, only_peer_community=False):
        from badges.models import Badge
        assessment_types = []
        badge_types = []
        if not only_self_completion and not only_peer_community:
            assessment_types.append(Badge.PEER)
            badge_types.append(Badge.SKILL)
        if not only_peer_skill and not only_peer_community:
            assessment_types.append(Badge.SELF)
            badge_types.append(Badge.COMPLETION)
        if not only_peer_skill and not only_self_completion:
            assessment_types.append(Badge.PEER)
            badge_types.append(Badge.COMMUNITY)
        if assessment_types and badge_types:
            return self.badges.filter(assessment_type__in=assessment_types,
                badge_type__in=badge_types)
        else:
            return Badge.objects.none()

    def get_upon_completion_badges(self, user):
        from badges.models import Badge, Award
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            self_completion_badges = self.get_project_badges(
                only_self_completion=True)
            upon_completion_badges = []
            for badge in self_completion_badges:
                missing_prerequisites = badge.prerequisites.exclude(
                    id__in=awarded_badges).exclude(
                    id__in=self_completion_badges.values('id'))
                if not missing_prerequisites.exists():
                    upon_completion_badges.append(badge.id)
            return Badge.objects.filter(id__in=upon_completion_badges)
        else:
            return Badge.objects.none()

    def get_awarded_badges(self, user, only_peer_skill=False):
        from badges.models import Badge, Award
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            project_badges = self.get_project_badges(only_peer_skill)
            return project_badges.filter(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_badges_in_progress(self, user):
        from badges.models import Badge, Award, Submission
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            attempted_badges = Submission.objects.filter(
                author=profile).values('badge_id')
            project_badges = self.get_project_badges(
                only_peer_skill=True)
            return project_badges.filter(
                id__in=attempted_badges).exclude(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_non_attempted_badges(self, user):
        from badges.models import Badge, Award, Submission
        if user.is_authenticated():
            profile = user.get_profile()
            awarded_badges = Award.objects.filter(
                user=profile).values('badge_id')
            attempted_badges = Submission.objects.filter(
                author=profile).values('badge_id')
            project_badges = self.get_project_badges(
                only_peer_skill=True)
            # Excluding both awarded and attempted badges
            # In case honorary award do not rely on submissions.
            return project_badges.exclude(
                id__in=attempted_badges).exclude(
                id__in=awarded_badges)
        else:
            return Badge.objects.none()

    def get_need_reviews_badges(self, user):
        from badges.models import Badge, Award, Submission
        if user.is_authenticated():
            profile = user.get_profile()
            project_badges = self.get_project_badges(
                only_peer_skill=True)
            peers_submissions = Submission.objects.filter(
                badge__id__in=project_badges.values('id')).exclude(
                author=profile)
            peers_attempted_badges = project_badges.filter(
                id__in=peers_submissions.values('badge_id'))
            need_reviews_badges = []
            for badge in peers_attempted_badges:
                peers_awards = Award.objects.filter(
                    badge=badge).exclude(user=profile)
                pending_submissions = peers_submissions.filter(
                    badge=badge).exclude(
                    author__id__in=peers_awards.values('user_id'))
                if pending_submissions.exists():
                    need_reviews_badges.append(badge.id)
            return project_badges.filter(
                id__in=need_reviews_badges)
        else:
            return Badge.objects.none()

    def get_non_started_next_projects(self, user):
        """To be displayed in the Join Next Challenges section."""
        if user.is_authenticated():
            profile = user.get_profile()
            joined = Participation.objects.filter(
                user=profile).values('project_id')
            return self.next_projects.exclude(
                id__in=joined)
        else:
            return Project.objects.none()

    @staticmethod
    def filter_activities(activities):
        from statuses.models import Status
        content_types = [
            ContentType.objects.get_for_model(Page),
            ContentType.objects.get_for_model(PageComment),
            ContentType.objects.get_for_model(Status),
            ContentType.objects.get_for_model(Project),
        ]
        return activities.filter(target_content_type__in=content_types)

    @staticmethod
    def filter_learning_activities(activities):
        pages_ct = ContentType.objects.get_for_model(Page)
        comments_ct = ContentType.objects.get_for_model(PageComment)
        return activities.filter(
            target_content_type__in=[pages_ct, comments_ct])
示例#15
0
class UserProfile(ModelBase):
    """Each user gets a profile."""
    object_type = 'http://activitystrea.ms/schema/1.0/person'

    username = models.CharField(max_length=255, default='', unique=True)
    full_name = models.CharField(max_length=255,
                                 default='',
                                 null=True,
                                 blank=True)
    password = models.CharField(max_length=255, default='')
    email = models.EmailField(unique=True, null=True)
    bio = models.TextField(blank=True, default='')
    image = models.ImageField(upload_to=determine_upload_path,
                              default='',
                              blank=True,
                              null=True,
                              storage=storage.ImageStorage())
    confirmation_code = models.CharField(max_length=255,
                                         default='',
                                         blank=True)
    location = models.CharField(max_length=255, blank=True, default='')
    featured = models.BooleanField()
    newsletter = models.BooleanField()
    discard_welcome = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)
    preflang = models.CharField(verbose_name='preferred language',
                                max_length=16,
                                choices=settings.SUPPORTED_LANGUAGES,
                                default=settings.LANGUAGE_CODE)

    user = models.ForeignKey(User, null=True, editable=False, blank=True)
    # TODO: enable when addition/edition of tags is implemented.
    # tags = TaggableManager(through=TaggedProfile)

    objects = UserProfileManager()

    def __unicode__(self):
        return self.full_name or self.username

    def following(self, model=None):
        """
        Return a list of objects this user is following. All objects returned
        will be ```Project``` or ```UserProfile``` instances. Optionally filter
        by type by including a ```model``` parameter.
        """
        if (model == 'Project' or isinstance(model, Project)
                or model == Project):
            relationships = Relationship.objects.select_related(
                'target_project').filter(source=self).exclude(
                    target_project__isnull=True)
            return [
                rel.target_project for rel in relationships
                if not rel.target_project.archived
            ]
        relationships = Relationship.objects.select_related(
            'target_user').filter(source=self).exclude(
                target_user__isnull=True)
        return [rel.target_user for rel in relationships]

    def followers(self):
        """Return a list of this users followers."""
        relationships = Relationship.objects.select_related('source').filter(
            target_user=self)
        return [rel.source for rel in relationships]

    def is_following(self, model):
        """Determine whether this user is following ```model```."""
        return model in self.following(model=model)

    def get_current_projects(self):
        projects = self.following(model=Project)
        projects_organizing = []
        projects_participating = []
        projects_following = []
        for project in projects:
            if project.organizers().filter(user=self).exists():
                project.relation_text = _('(organizing)')
                projects_organizing.append(project)
            elif project.participants().filter(user=self).exists():
                project.relation_text = _('(participating)')
                projects_participating.append(project)
            else:
                project.relation_text = _('(following)')
                projects_following.append(project)
        data = {
            'organizing': projects_organizing,
            'participating': projects_participating,
            'following': projects_following,
            'count': len(projects),
        }
        return data

    def get_past_projects(self):
        participations = Participation.objects.filter(user=self)
        current = participations.filter(project__archived=False,
                                        left_on__isnull=True)
        participations = participations.exclude(
            project__id__in=current.values('project_id'))
        past_projects = {}
        for p in participations:
            if p.project.slug in past_projects:
                past_projects[p.project.slug]['organizer'] |= p.organizing
            else:
                past_projects[p.project.slug] = {
                    'name': p.project.name,
                    'url': p.project.get_absolute_url(),
                    'organizer': p.organizing,
                    'image_url': p.project.get_image_url(),
                }
        return past_projects.values()

    @models.permalink
    def get_absolute_url(self):
        return ('users_profile_view', (), {
            'username': self.username,
        })

    def email_confirmation_code(self, url):
        """Send a confirmation email to the user after registering."""
        body = render_to_string('users/emails/registration_confirm.txt', {
            'confirmation_url': url,
        })
        subject = ugettext('Complete Registration')
        # During registration use the interface language to send email
        tasks.SendUserEmail.apply_async(args=(self, subject, body))

    def image_or_default(self):
        """Return user profile image or a default."""
        gravatarUrl = self.gravatar(54)
        avatar = '%s%s' % (settings.MEDIA_URL, '/images/member-missing.png')
        if self.image:
            avatar = '%s%s' % (settings.MEDIA_URL, self.image)
        elif gravatarUrl:
            avatar = gravatarUrl
        return mark_safe(avatar)

    def gravatar(self, size=54):
        hash = hashlib.md5(self.email.lower()).hexdigest()
        default = urlquote_plus(settings.DEFAULT_PROFILE_IMAGE)
        return GRAVATAR_TEMPLATE % {
            'size': size,
            'gravatar_hash': hash,
            'default': default,
            'rating': "g",
            'username': self.username,
        }

    def generate_confirmation_code(self):
        if not self.confirmation_code:
            self.confirmation_code = ''.join(
                random.sample(string.letters + string.digits, 60))
        return self.confirmation_code

    def set_password(self, raw_password, algorithm='sha512'):
        self.password = create_password(algorithm, raw_password)

    def check_password(self, raw_password):
        if '$' not in self.password:
            valid = (get_hexdigest('md5', '', raw_password) == self.password)
            if valid:
                # Upgrade an old password.
                self.set_password(raw_password)
                self.save()
            return valid

        algo, salt, hsh = self.password.split('$')
        return hsh == get_hexdigest(algo, salt, raw_password)

    @property
    def display_name(self):
        return self.full_name or self.username
示例#16
0
class Badge(ModelBase):
    """ Representation of a Badge """
    name = models.CharField(max_length=225, blank=False)
    slug = models.SlugField(unique=True, max_length=110)
    description = models.CharField(max_length=225, blank=False)
    requirements = RichTextField(blank=True, null=True)
    image = models.ImageField(upload_to=determine_upload_path,
                              default='',
                              blank=True,
                              null=True,
                              storage=storage.ImageStorage())
    prerequisites = models.ManyToManyField('self',
                                           symmetrical=False,
                                           blank=True,
                                           null=True)
    rubrics = models.ManyToManyField('badges.Rubric',
                                     related_name='badges',
                                     null=True,
                                     blank=True)
    logic = models.ForeignKey(
        'badges.Logic',
        related_name='badges',
        help_text=_('Regulates how the badge is awarded to users.'))
    all_groups = models.BooleanField(default=False)
    groups = models.ManyToManyField('projects.Project',
                                    related_name='badges',
                                    null=True,
                                    blank=True)
    creator = models.ForeignKey('users.UserProfile',
                                related_name='badges',
                                blank=True,
                                null=True)
    created_on = models.DateTimeField(auto_now_add=True, blank=False)

    def __unicode__(self):
        return "%s %s" % (self.name, _('Badge'))

    @models.permalink
    def get_absolute_url(self):
        return ('badges_show', (), {
            'slug': self.slug,
        })

    def get_image_url(self):
        # TODO: using project's default image until a default badge
        # image is added.
        missing = settings.STATIC_URL + 'images/missing-badge.png'
        image_path = self.image.url if self.image else missing
        return image_path

    def save(self):
        """Make sure each badge has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Badge.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Badge, self).save()

    def is_eligible(self, user):
        """Check if the user eligible for the badge.

        If some prerequisite badges have not been
        awarded returns False."""
        awarded_badges = Award.objects.filter(user=user).values('badge_id')
        return not self.prerequisites.exclude(id__in=awarded_badges).exists()

    def is_awarded_to(self, user):
        """Does the user have the badge?"""
        return Award.objects.filter(user=user, badge=self).count() > 0

    def award_to(self, user, submission=None):
        """Award the badge to the user.

        Returns None if no badge is awarded."""

        if not self.is_eligible(user):
            # If the user is not eligible the badge
            # is not awarded.
            return None

        if self.pending_peer_reviews(user, submission):
            # The user has not received the necessary satisfactory reviews
            # for the badge to be awarded.
            return None

        if submission:
            submission.pending = False
            submission.save()

        if self.logic.unique:
            # Do not award the badge if the user can not have the badge
            # more than once and it was already awarded.
            award, created = Award.objects.get_or_create(user=user, badge=self)
            return award if created else None

        return Award.objects.create(user=user, badge=self)

    def pending_peer_reviews(self, user, submission):
        if not self.logic.min_votes:
            return False
        assessments = Assessment.objects.filter(badge=self,
                                                assessed=user,
                                                ready=True)
        if submission:
            assessments = assessments.filter(submission=submission)
        else:
            assessments = assessments.filter(submission__isnull=True)
        if assessments.count() < self.logic.min_votes:
            # More votes needed.
            return True
        if not self.logic.min_avg_rating:
            return False
        avg_rating = Assessment.compute_average_rating(assessments)
        if avg_rating < self.logic.min_avg_rating:
            # Rating too low.
            return True

    def get_pending_submissions(self):
        """Submissions of users who haven't received the award yet"""
        return Submission.objects.filter(badge=self, pending=True)

    def get_peers(self, profile):
        from projects.models import Participation
        from users.models import UserProfile
        user_projects = Participation.objects.filter(
            user=profile).values('project__id')
        peers = Participation.objects.filter(project__in=user_projects)
        if not self.all_groups:
            badge_projects = self.groups.values('id')
            peers = peers.filter(project__in=badge_projects)
        return UserProfile.objects.filter(
            deleted=False,
            id__in=peers.values('user__id')).exclude(id=profile.id)

    def other_badges_can_apply_for(self):
        badges = Badge.objects.exclude(id=self.id).exclude(
            logic__submission_style=Logic.NO_SUBMISSIONS)
        badge_groups = self.groups.values('id')
        related_badges = badges.filter(groups__in=badge_groups).distinct()
        non_related_badges = badges.exclude(groups__in=badge_groups).distinct()
        return MultiQuerySet(related_badges, non_related_badges)

    def can_post_submission(self, user):
        if self.logic.submission_style == Logic.NO_SUBMISSIONS:
            return False
        if user.is_authenticated():
            profile = user.get_profile()
            if not profile.can_post():
                return False
            if not self.is_eligible(profile):
                return False
            awards = Award.objects.filter(user=profile, badge=self)
            if self.logic.unique and awards.exists():
                return False
            return True
        else:
            return False

    def can_give_to_peer(self, user):
        if not user.is_authenticated():
            return False
        if self.logic.submission_style == Logic.SUBMISSION_REQUIRED:
            return False
        if self.logic.min_votes != 1 or self.logic.min_avg_rating > 0:
            return False
        return True

    def can_review_submission(self, submission, user):
        # only authenticated users can review a submission
        if not user.is_authenticated():
            return False
        profile = user.get_profile()

        # user cannot review his/her own submission
        if profile == submission.author:
            return False

        # if this is a unique badge, only allow one review of submission
        if self.logic.unique and not submission.pending:
            return False

        # user can only submit one review
        assessments = submission.assessments.filter(assessor=profile)
        if assessments.exists():
            return False

        return True

    def get_adopters(self):
        from projects.models import Participation
        from users.models import UserProfile
        adopters = Participation.objects.filter(
            project__in=self.groups.values('id'),
            left_on__isnull=True).filter(Q(adopter=True) | Q(
                organizing=True)).values('user_id').distinct()
        return UserProfile.objects.filter(id__in=adopters)
示例#17
0
class Project(ModelBase):
    """Placeholder model for projects."""
    object_type = 'http://drumbeat.org/activity/schema/1.0/project'
    generalized_object_type = 'http://activitystrea.ms/schema/1.0/group'

    name = models.CharField(max_length=100)
    short_description = models.CharField(max_length=150)
    long_description = models.TextField(validators=[MaxLengthValidator(700)])

    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

    school = models.ForeignKey('schools.School',
                               related_name='projects',
                               null=True,
                               blank=True)

    detailed_description = models.ForeignKey('content.Page',
                                             related_name='desc_project',
                                             null=True,
                                             blank=True)
    sign_up = models.ForeignKey('content.Page',
                                related_name='sign_up_project',
                                null=True,
                                blank=True)

    image = models.ImageField(upload_to=determine_image_upload_path,
                              null=True,
                              storage=storage.ImageStorage(),
                              blank=True)

    slug = models.SlugField(unique=True, max_length=110)
    featured = models.BooleanField(default=False)
    created_on = models.DateTimeField(auto_now_add=True,
                                      default=datetime.datetime.now)

    under_development = models.BooleanField(default=True)
    not_listed = models.BooleanField(default=False)
    signup_closed = models.BooleanField(default=True)
    archived = models.BooleanField(default=False)

    clone_of = models.ForeignKey('projects.Project',
                                 blank=True,
                                 null=True,
                                 related_name='derivated_projects')

    imported_from = models.CharField(max_length=150, blank=True, null=True)

    objects = ProjectManager()

    class Meta:
        verbose_name = _('study group')

    def followers(self):
        return Relationship.objects.filter(target_project=self)

    def non_participant_followers(self):
        return self.followers().exclude(
            source__id__in=self.participants().values('user_id'))

    def participants(self):
        """Return a list of users participating in this project."""
        return Participation.objects.filter(project=self, left_on__isnull=True)

    def non_organizer_participants(self):
        return self.participants().filter(organizing=False)

    def organizers(self):
        return self.participants().filter(organizing=True)

    def is_organizing(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer = self.organizers().filter(user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer or is_superuser
        else:
            return False

    def is_participating(self, user):
        if user.is_authenticated():
            profile = user.get_profile()
            is_organizer_or_participant = self.participants().filter(
                user=profile).exists()
            is_superuser = user.is_superuser
            return is_organizer_or_participant or is_superuser
        else:
            return False

    def activities(self):
        activities = Activity.objects.filter(
            Q(project=self) | Q(target_project=self), ).exclude(
                verb='http://activitystrea.ms/schema/1.0/follow').order_by(
                    '-created_on')
        return activities

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('projects_show', (), {
            'slug': self.slug,
        })

    def save(self):
        """Make sure each project has a unique slug."""
        count = 1
        if not self.slug:
            slug = slugify(self.name)
            self.slug = slug
            while True:
                existing = Project.objects.filter(slug=self.slug)
                if len(existing) == 0:
                    break
                self.slug = "%s-%s" % (slug, count + 1)
                count += 1
        super(Project, self).save()

    def get_image_url(self):
        missing = settings.MEDIA_URL + 'images/project-missing.png'
        image_path = self.image.url if self.image else missing
        return image_path