Exemplo n.º 1
0
class ProjectGroupLimitFactors(object):

    # project_group billing-type에 따라 count에 제한을 둠.
    da_cnt_limit = db.IntField(default=100)
    project_cnt_limit = db.IntField(default=100)
    member_cnt_limit = db.IntField(default=100)

    # project 생성통제
    ban_create_project = db.BooleanField(default=False)

    # ip기반의 위치통제를 하기 위함
    use_firewall = db.BooleanField(default=False)
    firewall_rules = db.ListField(db.EmbeddedDocumentField(FirewallRule))

    def check_allowed_ip(self, ipaddr_str):
        ipaddr = ipaddress.ip_address(text(ipaddr_str))
        rules = [rule for rule in self.firewall_rules if rule.allow]

        if len(rules) == 0:
            return True

        return any((rule.match(ipaddr) for rule in rules))

    def is_firewall_working(self):
        return self.use_firewall and len(self.firewall_rules) > 0
Exemplo n.º 2
0
class ProjectGroupUser(JsonifyPatchMixin, db.Document):

    meta = {
        'indexes': [
            {
                'fields': ['project_group', 'user'],
                'unique': True
            },
        ],
    }

    ####################################################################
    # fields
    ####################################################################
    project_group = db.ReferenceField('ProjectGroup',
                                      required=True,
                                      reverse_delete_rule=mongoengine.CASCADE)
    user = db.ReferenceField('User',
                             required=True,
                             reverse_delete_rule=mongoengine.CASCADE)

    is_owner = db.BooleanField(default=False)
    is_moderator = db.BooleanField(default=False)
    is_termer = db.BooleanField(default=False)

    last_visited_at = db.DateTimeField(default=datetime.now)
    created_at = db.DateTimeField(default=datetime.now)

    # ui
    project_layout = db.StringField(default='boxed')

    render_template_path = "project_group/_members_tbl_row.html"

    ####################################################################
    # cached properties
    ####################################################################
    user_email = db.EmailField(max_length=255)

    ####################################################################
    # methods
    ####################################################################
    def __unicode__(self):
        return '{0}:{1}'.format(self.project_group.slug, self.user.email)

    def clean(self):
        self.user_email = self.user.email

    @classmethod
    def post_save(cls, sender, document, **kwargs):
        logger.debug('post save : %s' % document)
        on_joined_to_project_group.send(
            (document.user, document.project_group))
Exemplo n.º 3
0
class UserVerifyMixin(object):
    verified = db.BooleanField(default=False)

    def verify(self):
        if not self.verified:
            self.verified = True
            self.save()
            logger.debug(u'%s is verified' % self)
            on_verified_user.send(self)
        else:
            logger.warning(u'%s is already verified' % self)
Exemplo n.º 4
0
class ProjectRecommendationMixin(object):
    """프로젝트 추천하기."""

    picked = db.BooleanField(default=False)
    display_priority = db.IntField(default=0)

    @classmethod
    def _random(cls, limit, project_group, picked=False):
        u"""추천알고리즘없이 임의로 프로젝트 골라오기."""
        kw = dict(private=False,
                  visible=True,
                  demo=False,
                  project_group=project_group)
        if picked:
            kw['picked'] = True  # picked는 false일때는 true/false모두 챙긴다.

        projects = Project.objects(**kw).no_dereference().only('id')
        if len(projects):
            random.shuffle(list(projects))
            projects = [
                projects[i].reload() for i in range(min(limit, len(projects)))
            ]
            projects.sort(key=lambda x: -x.display_priority)
            return projects
        else:
            return []

    @classmethod
    def random(cls, limit=4, project_group=None):
        """추천알고리즘없이 임의로 프로젝트 골라오기.

        PROJECT:
        이 함수들은 성능이 좋지 않아서 PRODUCTION에서는 사용할 수 없습니다.
        batch로 project list를 준비하던가 해야겠음

        """
        if project_group is None:
            project_group = ProjectGroup.default()

        # picked priority
        selected = cls._random(limit=limit,
                               picked=True,
                               project_group=project_group)

        if len(selected) < limit:
            # 만약 limit만큼 채워지지 않았으면 조금 더 얻어오기
            chunks = cls._random(limit=limit - len(selected),
                                 project_group=project_group)
            selected.extend(chunks)

        # shuffle!
        # random.shuffle(selected)
        return selected
Exemplo n.º 5
0
class ProjectWaitingUserInbound(ProjectUserBase):

    project_group_user = db.ReferenceField(
        'ProjectGroupUser',
        required=True,
        reverse_delete_rule=mongoengine.CASCADE)
    """사용자가 가입요청을 했을 경우"""
    done = db.BooleanField(default=False)
    done_by = db.ReferenceField('User',
                                reverse_delete_rule=mongoengine.NULLIFY)
    done_at = db.DateTimeField(default=datetime.now)
    done_message = db.StringField()
    rejected = db.BooleanField(default=False)

    asked_at = db.DateTimeField(default=datetime.now)
    asked_message = db.StringField()

    render_template_path = 'project/_members_waiting_tbl_row.html'

    def clean(self):
        pgu = ProjectGroupUser.objects(
            project_group=self.project.project_group, user=self.user).first()
        if pgu is None:
            raise ValidationError('Invalid group-project-usermapping')
        else:
            self.project_group_user = pgu

        # cached property
        self.user_email = self.user.email

    def approve_and_get_new_project_user(self):
        if not self.project.is_new_member_available():
            return None

        project = self.project
        user = self.user

        self.delete()

        return ProjectUser(project=project, user=user).save()
Exemplo n.º 6
0
class ProjectGroupNotices(object):

    show_notices = db.BooleanField(default=True)
    notices = db.ListField(db.EmbeddedDocumentField(ProjectGroupNotice))
    # notices = db.ListField(ProjectGroupNoticeField())

    @property
    def queryset_notice(self):
        from erks.models import ProjectGroupNotice
        return ProjectGroupNotice.objects(project_group=self, use_yn=True)

    @property
    def queryset_qna(self):
        from erks.models import ProjectGroupQnA
        return ProjectGroupQnA.objects(project_group=self, use_yn=True)
Exemplo n.º 7
0
class FirewallRule(db.EmbeddedDocument):

    seq = db.IntField(default=0)
    allow = db.BooleanField(default=True)
    source = db.StringField(max_length=50, required=True)
    cidr = db.IntField(max_value=32, required=True)

    def to_ipcidr(self):
        return u"{0}/{1}".format(self.source, self.cidr)

    def match(self, ipaddr):
        # if isinstance(ipaddr, str) or isinstance(ipaddr, unicode):
        if isinstance(ipaddr, six.text_type):
            ipaddr = ipaddress.ip_address(text(ipaddr))
        return ipaddr in ipaddress.ip_network(self.to_ipcidr())
Exemplo n.º 8
0
class ProjectGroupGlossaryMasterMixin(object):
    use_glossary_master = db.BooleanField(default=False)

    @property
    def glossary_master(self):
        from erks.models import GlossaryMaster
        return GlossaryMaster.objects(project_group=self).first()

    # glossary_master = db.ReferenceField('GlossaryMaster')

    @property
    def queryset_master_term(self):
        from erks.models import Term
        if self.use_glossary_master and self.glossary_master:
            return Term.objects(glossary=self.glossary_master)
        else:
            return Term.objects(id='0' * 24)  # empty

    @property
    def queryset_master_term_request(self):
        from erks.models import TermMasterRequest
        if self.use_glossary_master and self.glossary_master:
            return TermMasterRequest.objects(
                glossary_master=self.glossary_master)
        else:
            return TermMasterRequest.objects(id='0' * 24)  # dummy

    @property
    def queryset_glossary(self):
        from erks.models import Glossary
        return Glossary.head_objects(project_group=self)

    def create_glossary_master(self):
        from erks.models import GlossaryMaster
        if self.glossary_master:
            raise ProjectGroupIntegrityError(
                gettext('프로젝트그룹 마스터용어집은 이미 존재합니다'))

        # glossary = GlossaryMaster.objects(project_group=self).first()
        # if glossary is None:
        glossary = GlossaryMaster()
        glossary.project_group = self
        glossary.glossary_name = self.slug  # temporary
        glossary.save()

        logger.debug('glossary_master is created.')
Exemplo n.º 9
0
class ProjectGroupMemberJoin(object):

    # members = db.ListField(db.ReferenceField('User'))

    use_join_with_re = db.BooleanField(default=False)
    use_join_with_domain = db.BooleanField(default=False)

    # 신규사용자에 대해 자동등록검사
    apply_for_newbie_always = db.BooleanField(default=False)

    join_domain_rules = db.ListField(db.StringField(max_length=1000))
    join_re_rules = db.ListField(db.StringField(max_length=1000))

    # 프로젝트 초대시 자동으로 그룹사용자 등록
    join_with_project_invatation = db.BooleanField(default=False)

    # 프로젝트그룹내 사용자를 검색해서 프로젝트에 초대할 수 있는지 여부
    can_search_member = db.BooleanField(default=True)

    # 프로젝트그룹내 사용자를 검색해서 프로젝트에 초대할 수 있는지 여부
    can_invite_oubound_user = db.BooleanField(default=False)

    def join(self, user):
        return ProjectGroupUser(project_group=self, user=user).save()

    def leave(self, user):
        ProjectGroupUser.objects(project_group=self, user=user).delete()

    def test_joinrule(self, email):
        chunks = email.split('@')
        if len(chunks) < 2:
            return False

        if self.use_join_with_domain and \
                any([
                    domain == chunks[1]
                    for domain in self.join_domain_rules
                ]):
            return True

        return False

    def clean(self):
        self.join_domain_rules = list(set(self.join_domain_rules))
        self.join_domain_rules = list(
            filter(lambda x: len(x), self.join_domain_rules))

        self.join_re_rules = list(set(self.join_re_rules))
        self.join_re_rules = list(filter(lambda x: len(x), self.join_re_rules))
Exemplo n.º 10
0
class AdminMixin(object):
    @property
    def is_admin(self):
        return self.admin
    admin = db.BooleanField(default=False)
Exemplo n.º 11
0
class ProjectUser(ProjectUserBase, ProjectUserReportSubscriptionMixin):
    """project에 속한 user관리."""

    project_group_user = db.ReferenceField(
        'ProjectGroupUser',
        required=True,
        reverse_delete_rule=mongoengine.CASCADE)

    is_owner = db.BooleanField(default=False)
    last_visited_at = db.DateTimeField(default=datetime.now)

    # # for modeling
    # is_modeler = db.BooleanField(default=False)
    # can_manage_all_models = db.BooleanField(default=True)
    # manageable_models = db.ListField(db.ReferenceField(
    #     'Model', reverse_delete_rule=mongoengine.PULL))

    # # for terming
    # is_termer = db.BooleanField(default=False)
    # can_manage_all_glossaries = db.BooleanField(default=True)
    # manageable_glossaries = db.ListField(db.ReferenceField(
    #     'GlossaryBase', reverse_delete_rule=mongoengine.PULL))

    # ui
    project_layout = db.StringField(default='boxed')

    render_template_path = 'project/_members_tbl_row.html'

    def clean(self):
        pgu = ProjectGroupUser.objects(
            project_group=self.project.project_group, user=self.user).first()
        if pgu is None:
            raise ValidationError('Invalid project-group-user-mapping')
        else:
            self.project_group_user = pgu

        # cached property
        self.user_email = self.user.email

    def visit(self):
        if self.project.demo:
            return
        # self.last_visited_at = datetime.now()
        # self.save()
        self.update(last_visited_at=datetime.now())

    @property
    def grades(self):
        ret = []
        if self.is_owner:
            ret.append('owner')
        if self.is_modeler:
            ret.append('modeler')
        if self.is_termer:
            ret.append('termer')
        if len(ret) == 0:
            ret.append('member')
        return ret

    def __unicode__(self):
        return u'%s:%s:%s' % (self.project, self.user, ','.join(self.grades))
Exemplo n.º 12
0
class ProjectUserReportSubscriptionMixin(object):
    subscribed_report_model_glossary = db.BooleanField(default=False)
    subscribed_report_model_schema = db.BooleanField(default=False)
    subscribed_report_model_change = db.BooleanField(default=False)
Exemplo n.º 13
0
class ProjectGroup(
        db.Document,
        ProjectGroupNotices,
        ProjectGroupAppereance,
        ProjectGroupLimitFactors,
        ProjectGroupMy,
        ProjectGroupMemberJoin,
        ProjectGroupGlossaryMasterMixin,
        # BillingMixin
):
    """프로젝트를 그룹하여 관리하는 객체.
    project는 한개의 group에 종속된다.
    default라는 이름으로 기본 project_group이 항상 존재해야 함.
    """

    meta = {
        'indexes': [
            {
                'fields': ['slug'],
                'unique': True
            },
        ],
    }

    ####################################################################
    # fields
    ####################################################################
    title = db.StringField(required=True, max_length=255, min_length=2)
    slug = db.StringField(required=True, max_length=255, min_length=2)
    description = db.StringField(required=True, max_length=4000)
    external_homepage_url = db.URLField(max_length=1000)

    private = db.BooleanField(default=False)
    visible = db.BooleanField(default=True)

    created_at = db.DateTimeField(default=datetime.now, required=True)
    created_by = db.ReferenceField('User')

    allow_subscribe_all_project_changes = db.BooleanField(default=False)

    ####################################################################
    # properties
    ####################################################################
    @property
    def queryset_project(self):
        from erks.erks_bps.project.models import Project
        return Project.objects(project_group=self)

    @property
    def queryset_project_group_user(self):
        return ProjectGroupUser.objects(project_group=self)

    @property
    def url(self):
        return url_for('project_group.list_projects', slug=self.slug)

    @property
    def is_not_default(self):
        return self.slug != 'default'

    @property
    def is_default(self):
        return self.slug == 'default'

    @classmethod
    def default(cls):
        slug = current_app.config['DEFAULT_PROJECT_GROUP_SLUG']
        default_project_group = ProjectGroup.objects(slug=slug).first()

        # if not default_project_group.theme_key and current_app.config['DEFAULT_PROJECT_GROUP_THEME_KEY']:
        #     default_project_group.theme_key = current_app.config['DEFAULT_PROJECT_GROUP_THEME_KEY']

        return default_project_group

    ####################################################################
    # methods
    ####################################################################
    def __unicode__(self):
        return self.slug

    def clean(self):
        # project_group에 속한 여러개의 mixins의
        # clean method를 차례로 호출
        for base in ProjectGroup.__bases__:
            try:
                base.clean(self)
            except AttributeError:
                pass

    def save_as_random_slug(self):
        logger.debug("save_as_random_slug called")
        try:
            # import pdb; pdb.set_trace()
            self.slug = self.slug + str(random.randrange(1, 1000))
            self.save()
            logger.debug("slug {0}, "
                         "save_as_random_slug saved".format(self.slug))
        except mongoengine.errors.NotUniqueError:
            self.save_as_random_slug()

    def save(self, *args, **kwargs):
        is_new = not self.id
        self.is_free = False  # project_group always shouldn't be free.
        ret = super(ProjectGroup, self).save(*args, **kwargs)
        # if kwargs.get('emit_signals', True) and self.is_not_default:
        if is_new:
            on_created_project_group.send(self)
        else:
            on_changed_project_group.send(self)
        return ret
Exemplo n.º 14
0
class Project(
        JsonifyPatchMixin,
        AuditableMixin,
        db.Document,
        # ProjectBillingMixin,
        # ProjectGlossaryDerivedMixin,
        ProjectInvatationMixin,
        # ProjectRecommendationMixin,
        # ProjectReportMixin,
        # ProjectSchemaCollectorMixin,
        ProjectUserMixin,
):

    title = db.StringField(required=True, max_length=40, min_length=2)
    # created_at = db.DateTimeField(default=datetime.now, required=True)

    private = db.BooleanField(default=False)
    visible = db.BooleanField(default=True)
    demo = db.BooleanField(default=False)

    description = db.StringField()
    contact = db.StringField()
    profile_imgf = db.ImageField(
        collection_name='project_images',
        size=(600, 600, True),
        thumbnail_size=(140, 140, True),
    )
    project_group = db.ReferenceField('ProjectGroup', required=True)
    project_group_managed = db.BooleanField(default=False)

    # modified_at = db.DateTimeField(
    #     default=datetime.now, required=True)

    meta = {'ordering': ['-modified_at', '-created_at']}

    ####################################################################
    # PROJECT내에서 사용되는 GRADE
    ####################################################################
    ORGANIZER = u'owner'
    MEMBER = u'member'
    MODELER = u'modeler'
    TERM_MANAGER = u'termer'
    WAITING_MEMBER = u'waiting_member'
    GUEST = u'guest'

    @property
    def base_html(self):
        if self.project_group:
            return self.project_group.project_base_html
        else:
            return "project/base.html"

    @property
    def base4erc_html(self):
        if current_user.is_authenticated:
            if self.project_group:
                return self.project_group.base4erc_html
            else:
                return "base4erc.html"
        else:
            return ProjectGroup.default().base4erc_html

    ####################################################################
    # properties
    ####################################################################
    @property
    def queryset_project_user(self):
        from erks.models import ProjectUserBase
        return ProjectUserBase.objects(project=self)

    @property
    def queryset_post(self):
        from erks.models import Post
        return Post.objects(project=self)

    # @property
    # def queryset_glossary(self):
    #     from erks.models import GlossaryBase
    #     return GlossaryBase.head_objects(project=self)

    @property
    def queryset_user(self):
        '''todo: mongodb와 document 설계 한계로 인해서 사용자객체의 queryset
        형태로 구현하기에는 현재로서는 어려워보임.'''

        # code = """
        # function(field) {
        #     var docs = [];
        #     db['project_user_base'].find(
        #        {project: ObjectId(options.project_id)}
        #    ).forEach(function(doc) {
        #         //docs.push(db[collection].findOne({_id: doc.user}));
        #         docs.push(doc.user);
        #     });
        #     return docs;
        # }
        # """
        # return User.objects.exec_js(code, 'id', project_id=str(self.id))

        raise NotImplementedError()

    # @property
    # def context_term_managers(self):
    #     '''현재 project, glossary에 속해있는 용어관리자를 return'''
    #     return [
    #         entry.user
    #         for entry in self.queryset_project_user.filter(
    #             is_termer=True).only('user', 'can_manage_all_glossaries',
    #                                  'manageable_glossaries')
    #         if entry.can_manage_all_glossaries or (
    #             entry.manageable_glossaries and
    #             g.glossary in entry.manageable_glossaries)
    #     ]

    @property
    def owner(self):
        project_owner = self.queryset_project_user.filter(
            is_owner=True).only('user').first()
        return project_owner.user

    @property
    def members(self):
        # TODO: 속도개선을 위해 iterable하고 container type의 객체를 return하도록
        return [
            entry.user for entry in self.queryset_project_user.only('user')
        ]

    @property
    def term_managers(self):
        # TODO: 속도개선을 위해 iterable하고 container type의 객체를 return하도록
        return [
            entry.user for entry in self.queryset_project_user.filter(
                is_termer=True).only('user')
        ]

    @property
    def modelers(self):
        # TODO: 속도개선을 위해 iterable하고 container type의 객체를 return하도록
        return [
            entry.user for entry in self.queryset_project_user.filter(
                is_modeler=True).only('user')
        ]

    @property
    def url(self):
        return url_for('project.index', project_id=self.id)

    @property
    def external_url(self):
        return url_for('project.index', project_id=self.id, _external=True)

    ####################################################################
    # queryset
    ####################################################################
    @db.queryset_manager
    def demo_objects(doc_cls, queryset):
        return queryset.filter(demo=True)

    @db.queryset_manager
    def visible_objects(doc_cls, queryset):
        '''프로젝트포털에 노출가능한 것만 보여준다.'''
        # TODO: 내 것은 무조건 보여야 한다.
        return queryset.filter((Q(visible=True) | Q(visible=None))
                               & Q(demo=False))

    ####################################################################
    # methods
    ####################################################################
    def save(self, *args, **kwargs):
        # NOTIFY_MAP = {
        #     'title': dict(message=lazy_gettext(u'프로젝트명이 \'%s\'로 변경되었습니다.' % self.title, typ='project'),
        #     'private': dict(message=lazy_gettext(u'이 프로젝트는 %s입니다.' % (lazy_gettext(u'공개', lazy_gettext(u'비공개')[self.private], typ='project'),
        #     'visible': dict(message=lazy_gettext(u'이 프로젝트는 %s.' % (lazy_gettext(u'검색되지 않습니다.', lazy_gettext(u'검색에 노출됩니다.')[self.visible], typ='project'),
        #     'description': dict(message=lazy_gettext(u'상세 설명 부분이 변경되었습니다.', typ='project'),
        #     'profile_imgf': dict(message=lazy_gettext(u'프로젝트 이미지가 변경되었습니다.', typ='project'),
        # }

        if self.id:
            # [self.notify(**NOTIFY_MAP[fieldname])
            #     for fieldname in self._changed_fields
            #     if fieldname in NOTIFY_MAP]
            # OWNER변경에 대한 NOTIFICATION처리, OWNER가 종종 알수없이 _changed_fields에
            # 들어가있다.
            # if 'owner' in self._changed_fields:
            #     self.notify(message=lazy_gettext(u'{{user.email}} 사용자는 관리자입니다.',
            #                 user=self.owner, typ='user')
            #     on_changed_project_owner.send(self)
            on_changed_project.send(self)
            ret = super(Project, self).save(*args, **kwargs)
        else:
            # You can only reference documents once they have been saved to the
            # database
            ret = super(Project, self).save(*args, **kwargs)
            on_created_project.send(self)
            # on_changed_project_owner.send(self)
            # self.notify(
            #     message=lazy_gettext(u'프로젝트가 생성되었습니다 by {{user.email}}', user=self.owner, typ='project')
            # self.notify(message=lazy_gettext(u'{{user.email}} 사용자는 관리자입니다.',
            #             user=self.owner, typ='user')
        return ret

    def __unicode__(self):
        return self.title

    def __lt__(self, other):
        return str(self) < str(other)

    def __gt__(self, other):
        return str(self) > str(other)

    def clean(self):

        # free-project-cannot-be-private
        # self.id가 없을때 product를 참고하면 오류발
        if current_app.config['BILLING']:
            if self.id and \
               (self.product is None or not self.product.support_private):
                self.private = False
                self.visible = True

        # project-group-check
        if self.project_group is None:
            self.project_group = ProjectGroup.default()

    def get_grade(self, user):
        from erks.models import (
            ProjectUser,
            ProjectUserBase,
            ProjectWaitingUserInbound,
        )
        # 미로그인사용자도 사용할 수 있는 함수
        # if user.is_active:
        #     if user == self.owner:
        #         return self.ORGANIZER
        #     elif user in self.modelers:
        #         return self.MODELER
        #     elif user in self.term_managers:
        #         return self.TERM_MANAGER
        #     elif user in self.members:
        #         return self.MEMBER
        #     elif user in self.waiting_members:
        #         return self.WAITING_MEMBER
        #     # elif user in self.invited_members:
        #     #     return self.WAITING_MEMBER
        # else:
        #     logger.debug('user is not active.')
        # return self.GUEST
        if user.is_active:
            entry = ProjectUserBase.objects(project=self, user=user).first()
            if entry:
                if isinstance(entry, ProjectUser):
                    if entry.is_owner:
                        return self.ORGANIZER
                    elif entry.is_modeler:
                        return self.MODELER
                    elif entry.is_termer:
                        return self.TERM_MANAGER
                    else:
                        return self.MEMBER
                elif isinstance(entry, ProjectWaitingUserInbound):
                    return self.WAITING_MEMBER
        else:
            logger.debug('user is not active.')
        return self.GUEST

    def _get_grades(self, user):
        from erks.models import (
            ProjectUser,
            ProjectUserBase,
            ProjectWaitingUserInbound,
        )
        grades = []
        if user.is_active:
            entry = ProjectUserBase.objects(project=self, user=user).first()
            if isinstance(entry, ProjectUser):
                if entry.is_owner:
                    grades.append(self.ORGANIZER)
                if entry.is_modeler:
                    grades.append(self.MODELER)
                if entry.is_termer:
                    grades.append(self.TERM_MANAGER)
            if not grades:
                if isinstance(entry, ProjectUser):
                    grades.append(self.MEMBER)
                elif isinstance(entry, ProjectWaitingUserInbound):
                    grades.append(self.WAITING_MEMBER)
            if grades:
                return grades
        return [self.GUEST]

    def get_grades(self, user):
        def _(grade):
            return {
                'owner': {
                    'label': 'label-primary',
                    'grade': gettext(u'프로젝트 관리자')
                },
                'member': {
                    'label': 'label-warning',
                    'grade': gettext(u'일반회원')
                },
                'modeler': {
                    'label': 'label-success',
                    'grade': gettext(u'모델러')
                },
                'termer': {
                    'label': 'label-info',
                    'grade': gettext(u'용어 관리자')
                },
                'waiting_member': {
                    'label': 'label-default',
                    'grade': gettext(u'손님(등록 대기중)')
                },
                'guest': {
                    'label': 'label-default',
                    'grade': gettext(u'손님')
                }
            }[grade]

        return [_(grade) for grade in self._get_grades(user)]

    def check_to_enter(self, user=None):
        from erks.models import (
            ProjectUser, )
        '''project에 입장할 수 있는지를 검사'''
        if self.demo:
            return True

        # TODO: 이게 맞나요?
        if not current_user.is_active:
            return False

        if user is None:
            user = current_user._get_current_object()

        is_member = ProjectUser.objects(
            project=self,
            user=user).only('id').no_dereference().first() is not None
        return not self.private or is_member

    # def count_entities(self):
    #     from erks.erks_bps.erc.models import Entity
    #     return len(Entity.objects(prjId=str(self.id)))

    # def count_terms(self):
    #     from erks.erks_bps.term.models import Term
    #     return len(Term.objects(project=self))

    # def is_custom_img(self):
    #     return self.profile_imgf

    # def is_new(self):
    #     """
    #     project가 새 것인지를 판단하기
    #     주제영역이 하나라도 구성되어 있으면 알림을 주지 않기 위해.
    #     """
    #     from erks.erks_bps.erc.models import SubjectArea
    #     return SubjectArea.objects(prjId=str(self.id)).first() is None

    def get_profile_img_url(self, thumbnail=False):
        """binary값 기준으로 무작위로 profile image를 골라준다."""

        # 샘플이미지파일 개수
        SAMPLE_IMG_CNT = 5

        # TODO: 매번계산하므로 성능상 불리. 개선필요하다.
        random_number = sum(
            map(ord, list(hashlib.md5(
                self.id.binary).hexdigest()))) % SAMPLE_IMG_CNT + 1
        if self.profile_imgf:
            return url_for('project.profile_img', project_id=self.id)
        else:
            if self.project_group and self.project_group.theme_key in THEME_KEYS:
                filename = '%01s/img/Project_thumb_768x573_%02d.jpg' % (
                    self.project_group.theme_key, random_number)
            else:
                filename = 'img/r3/Project_thumb_768x573_%02d.jpg' % (
                    random_number)
            return url_for('static', filename=filename)

    def destroy(self):
        '''project 삭제처리. project에 속한 모든 resource를 삭제하므로
        경우에 따라 heavy할 수 있기 때문에
        가급적이면 web-request에서 처리하지 않는 것을 권장'''

        from erks.erks_bps.erc.models import (Model, Domain, SubjectArea,
                                              Entity, Relation, Lock)

        # delete models
        Model.objects(prjId=str(self.id)).delete()

        # domain
        Domain.objects(prjId=str(self.id)).delete()

        # delete subjectarea
        SubjectArea.objects(prjId=str(self.id)).delete()

        # delete entities
        Entity.objects(prjId=str(self.id)).delete()

        # delete relation
        Relation.objects(prjId=str(self.id)).delete()

        # delete lock
        Lock.objects(prjId=str(self.id)).delete()

        # delete project
        self.delete()
Exemplo n.º 15
0
class ProjectInvatationMixin(object):

    # 사용자도 멤버초대를 할 수 있는지
    allow_invitation_by_member = db.BooleanField(default=True)

    # TODO: 이 필드는 더 이상 사용하지 않습니다. 정리해주세요.
    # waiting_members = db.ListField(db.ReferenceField('User'))
    # invited_members = db.ListField(db.ReferenceField('User'))
    # auto_approve_requested_user = db.BooleanField(default=False)
    # auto_approve_invite_user = db.BooleanField(default=False)
    # 사용하지 않는 필드모음 끝.

    @property
    def waiting_invited_members(self):
        """프로젝트에 초대된 멤버목록을 보여줍니다."""
        from erks.models import ProjectWaitingUserOutbound
        cls = ProjectWaitingUserOutbound
        return (entry.user for entry in cls.objects(project=self).only('user'))

    @property
    def waiting_requested_members(self):
        """프로젝트에 가입요청한 멤버목록을 보여줍니다."""
        from erks.models import ProjectWaitingUserInbound
        cls = ProjectWaitingUserInbound
        return (entry.user for entry in cls.objects(project=self).only('user'))

    @property
    def members_cnt(self):
        '''project의 의미있는 member는 가입된 사용자 수 + 초대된 사용자 수.
        프로젝트 구성원이 의지적으로 포함시키지 않은 request member는 제외한다.'''
        from erks.models import ProjectUserBase
        return ProjectUserBase.objects(project=self).count() - \
            len(list(self.waiting_requested_members))

    def _available_member_cnt(self):
        from erks.models import ProjectUser, ProjectWaitingUserOutbound
        members_cnt = ProjectUser.objects(project=self).count()
        waiting_invited_members_cnt = ProjectWaitingUserOutbound.objects(
            project=self).count()
        return (self.product.member_cnt_limit - members_cnt -
                waiting_invited_members_cnt)

    def is_new_member_available(self, new_member_cnt=1):
        """새로운 멤버를 받을 수 있는지 체크."""
        if current_app.config['BILLING']:
            product = self.product
            if product is None:
                return False
            elif product.member_cnt_limit == 0:
                return True
            else:
                return self._available_member_cnt() - new_member_cnt >= 0
        else:
            return True

    def invite(self, email, inviter):
        '''email로 초대하기 (외부 사용자를 포함해야 하므로 사용자객체 아님)
        여러가지 방향이 있었지만 현재는 invite의 경우 별도의 승인없이 무조건 편입한다.
        invite는 의지적인 행동이기 때문에 별다른 검증을 거치지 않는 것으로 process 수립

        todo: code is messy. please tide up.
        '''

        from erks.models import ProjectUser, ProjectWaitingUserOutbound
        logger.debug('inviting %s', email)
        pg = self.project_group

        if (self.get_grade(inviter) == self.ORGANIZER or
                self.allow_invitation_by_member) and \
                self.is_new_member_available():

            try:
                user = User.objects.get(email=email)
                pgu = pg.queryset_member.filter(user=user).first()
                if pgu:
                    try:
                        ProjectUser(project=self,
                                    user=user,
                                    project_group_user=pgu).save()
                        ret = True
                        logger.debug('inviting process for inbound-user(%s)' %
                                     email)
                    except NotUniqueError:
                        logger.warning('already registered project-member(%s)',
                                       email)
                        ret = False
                else:
                    logger.warning('user(%s)-does-not-in-project-group(%s).',
                                   email, pg)
                    ret = False
            except User.DoesNotExist:
                if pg.can_invite_oubound_user:
                    try:
                        invitee = ProjectWaitingUserOutbound(
                            project=self, user=email).save()
                        invitee.sendmail()
                        ret = True
                        logger.debug('inviting process for outbound-user(%s)' %
                                     email)
                    except NotUniqueError:
                        logger.warning('already registered outbound-user')
                        ret = False
                else:
                    logger.warning(
                        'outbound user(%s) cannot'
                        ' join project-group(%s).'
                        ' check the pref.', email, pg)
                    ret = False
        else:
            ret = False

        return ret

    def leave(self, user):
        '''Project탈퇴는 MEMBER는 가능, OWNER는 불가능하다.
        탈퇴 성공여부를 True/False로 리턴'''
        from erks.models import ProjectUser
        entry = ProjectUser.objects(project=self, user=user,
                                    is_owner=False).first()
        if entry:
            entry.delete()
            return True
        else:
            return False

    def request_to_join(self, user, message=u''):
        '''외부 사용자의 의지적인 합류 요청.
        '''
        from erks.models import ProjectWaitingUserInbound
        try:
            ProjectWaitingUserInbound(project=self,
                                      user=user,
                                      asked_message=message).save()
            logger.debug('inviting process for inbound-user(%s)' % user)
            ret = True
        except NotUniqueError:
            logger.warning('already registered project-waiting-member')
            ret = False
        return ret