Ejemplo n.º 1
0
    def delete_hackathon_notice(self, notice_id):
        hackathon_notice = HackathonNotice.objects(id=notice_id).first()
        if not hackathon_notice:
            return not_found('Hackathon notice not found')

        hackathon_notice.delete()
        return ok()
Ejemplo n.º 2
0
    def check_notice_and_set_read_if_necessary(self, id):
        hackathon_notice = HackathonNotice.objects(id=id).first()
        if hackathon_notice:
            user = g.user
            if not user or user.id != hackathon_notice.receiver.id:  # not the user
                return ok()

            hackathon_notice.is_read = True
            if hackathon_notice.event == HACK_NOTICE_EVENT.HACK_PLAN:  # set is_read = True if dev_plan is complete
                user = hackathon_notice.receiver
                hackathon = hackathon_notice.hackathon
                team = Team.objects(members__user=user,
                                    hackathon=hackathon).first()
                if team:
                    if not team.dev_plan:  # the dev_plan isn't submitted
                        hackathon_notice.is_read = False
                    elif hackathon.config.get(
                            HACKATHON_CONFIG.REAL_NAME_AUTH_21V, False):
                        self.create_hackathon_notice(
                            hackathon.id,
                            HACK_NOTICE_EVENT.HACK_REGISTER_AZURE,
                            HACK_NOTICE_CATEGORY.HACKATHON, {'receiver': user})

            hackathon_notice.save()
            return ok()
Ejemplo n.º 3
0
    def delete_hackathon_notice(self, notice_id):
        hackathon_notice = HackathonNotice.objects(id=notice_id).first()
        if not hackathon_notice:
            return not_found('Hackathon notice not found')

        hackathon_notice.delete()
        return ok()
Ejemplo n.º 4
0
    def update_hackathon_notice(self, body):
        hackathon_notice = HackathonNotice.objects(id=body.get('id')).first()
        if not hackathon_notice:
            return not_found("hackathon_notice not found")

        hackathon_notice.content = body.get("content", hackathon_notice.content)
        hackathon_notice.link = body.get("link", hackathon_notice.link)

        hackathon_notice.save(validate=False)
        return hackathon_notice.dic()
Ejemplo n.º 5
0
    def test_read_user_notice(self, user1):
        self.login(user1)

        # init new unread msg
        hackathon_notice = HackathonNotice(
            content='',
            link='',
            event=HACK_NOTICE_EVENT.HACK_CREATE,
            category=HACK_NOTICE_CATEGORY.HACKATHON,
            receiver=user1,
            creator=user1,
        )
        hackathon_notice.save()
        assert not hackathon_notice.is_read

        # test read msg
        payload = self.client.put("/api/user/notice/read", json_data=dict(id=str(hackathon_notice.id)))
        assert payload['code'] == 200
        hackathon_notice = HackathonNotice.objects(id=str(hackathon_notice.id)).first()
        assert hackathon_notice.is_read
Ejemplo n.º 6
0
    def update_hackathon_notice(self, body):
        hackathon_notice = HackathonNotice.objects(id=body.get('id')).first()
        if not hackathon_notice:
            return not_found("hackathon_notice not found")

        hackathon_notice.content = body.get("content",
                                            hackathon_notice.content)
        hackathon_notice.link = body.get("link", hackathon_notice.link)
        hackathon_notice.category = body.get("category",
                                             hackathon_notice.category)
        hackathon_notice.update_time = self.util.get_now()

        hackathon_notice.save(validate=False)
        return hackathon_notice.dic()
Ejemplo n.º 7
0
    def check_notice_and_set_read_if_necessary(self, id):
        hackathon_notice = HackathonNotice.objects(id=id).first()
        if hackathon_notice:
            user = g.user
            if not user or user.id != hackathon_notice.receiver.id:  # not the user
                return ok()

            hackathon_notice.is_read = True
            if hackathon_notice.event == HACK_NOTICE_EVENT.HACK_PLAN:  # set is_read = True if dev_plan is complete
                user = hackathon_notice.receiver
                hackathon = hackathon_notice.hackathon
                team = Team.objects(members__user=user,
                                    hackathon=hackathon).first()
                if team:
                    if not team.dev_plan:  # the dev_plan isn't submitted
                        hackathon_notice.is_read = False
            hackathon_notice.save()
            return ok()
Ejemplo n.º 8
0
    def check_notice_and_set_read_if_necessary(self, id):
        hackathon_notice = HackathonNotice.objects(id=id).first()
        if hackathon_notice:
            user = g.user
            if not user or user.id != hackathon_notice.receiver.id:  # not the user
                return ok()

            hackathon_notice.is_read = True
            if hackathon_notice.event == HACK_NOTICE_EVENT.HACK_PLAN:  # set is_read = True if dev_plan is complete
                user = hackathon_notice.receiver
                hackathon = hackathon_notice.hackathon
                team = Team.objects(members__user=user, hackathon=hackathon).first()
                if team:
                    if not team.dev_plan:  # the dev_plan isn't submitted
                        hackathon_notice.is_read = False
                    elif hackathon.config.get(HACKATHON_CONFIG.REAL_NAME_AUTH_21V, False):
                        self.create_hackathon_notice(hackathon.id, HACK_NOTICE_EVENT.HACK_REGISTER_AZURE,
                                                     HACK_NOTICE_CATEGORY.HACKATHON, {'receiver': user})

            hackathon_notice.save()
            return ok()
Ejemplo n.º 9
0
    def get_hackathon_notice_list(self, body):
        """
        list hackathon notices, notices are paginated, can be filtered by hackathon_name, event and category,
        can be ordered by update_time, event and category.

        :type body: Context
        :param body: valid key/values(all key/values are optional)
            body = {
                hackathon_name: string,                  // filter by hackathon_name, default unfiltered
                filter_by_user: '******' | 'all',         // filter by user, default filter all notice that has specfic receivers
                category: 'int[,int...]',                // filter by category, default unfiltered
                event: 'int[,int...]',                   // filter by event, default unfiltered
                order_by: 'time' | 'event' | 'category', // order by update_time, event, category, default by time
                page: int,                               // page number after pagination, start from 1, default 1
                per_page: int                            // items per page, default 1000
            }

        :return: json style text, see util.Utility

        ::Example:
        : body = { order_by: 'time', category: '1,2,3', page: 1, per_page: 6 }
            search first 6 notices ordered by time, filtered by: category in [1,2,3]
        : body = { hackathon_name: 'hackathon', event: '1', order_by: 'event' }
            search first 1000 notices ordered by event, filtered by event == 1 and hackathon_name == 'hackathon'
        """

        hackathon_name = body.get("hackathon_name")
        filter_by_user = body.get("filter_by_user", "")
        notice_category = body.get("category")
        notice_event = body.get("event")
        order_by = body.get("order_by", "time")
        page = int(body.get("page", 1))
        per_page = int(body.get("per_page", 1000))

        hackathon_filter = Q()
        category_filter = Q()
        event_filter = Q()
        user_filter = Q(receiver=None)
        is_read_filter = Q()
        order_by_condition = '-update_time'

        if hackathon_name: #list notices that belong to specfic hackathon
            hackathon = Hackathon.objects(name=hackathon_name).only('name').first()
            if hackathon:
                hackathon_filter = Q(hackathon=hackathon)
            else:
                return not_found('hackathon_name not found')
        else: #only list online hackathons' notices or notices that not belong to any hackathon
            online_hackathon = Hackathon.objects(status=HACK_STATUS.ONLINE)
            hackathon_filter = Q(hackathon__in=online_hackathon) | Q(hackathon=None)

        if filter_by_user:  # only return notices that are sent to the login user
            user = None
            if self.user_manager.validate_login():
                user = g.user
                user_filter = Q(receiver=user)
                if filter_by_user == 'unread':
                    is_read_filter = Q(is_read=False)
            else:
                return bad_request("please login first")

        if notice_category:
            notice_category_tuple = tuple([int(category) for category in notice_category.split(',')])
            category_filter = Q(category__in=notice_category_tuple)
        if notice_event:
            notice_event_tuple = tuple([int(event) for event in notice_event.split(',')])
            event_filter = Q(event__in=notice_event_tuple)

        if order_by == 'category':
            order_by_condition = '+category'
        elif order_by == 'event':
            order_by_condition = '+event'
        else:
            order_by_condition = '-update_time'

        pagination = HackathonNotice.objects(
            hackathon_filter & category_filter & event_filter & user_filter & is_read_filter
        ).order_by(
            order_by_condition
        ).paginate(page, per_page)

        def func(hackathon_notice):
            return hackathon_notice.dic()

        # return serializable items as well as total count
        return self.util.paginate(pagination, func)
Ejemplo n.º 10
0
    def create_hackathon_notice(self, hackathon_id, notice_event, notice_category, body={}):
        """
        create hackathon notice with hackathon_id, notice_event, notice_category.
        notice 'content' and 'link' can be included in body (optional)

        :type hackathon_id: int
        :param hackathon_id: id of hackathon that the notice belongs to (-1 if the notice doesn't belong to a specfic hackathon)

        :type notice_event: Class HACK_NOTICE_EVENT
        :param notice_event: event that the notice is triggered by, used for notice filtering (see get_hackathon_notice_list())
                             more specfic than notice_category, new events can be added without disturbing front-end code

        :type notice_category: Class HACK_NOTICE_CATEGORY
        :param notice_category: category that the notice belongs to, used for notice filtering and notice properties display
                                at front-end (e.g. icons/descriptions, see oh.manage.notice.js & oh.site.hackathon.js),
                                more general than notice_event, if you want to add a new category in HACK_NOTICE_CATEGORY,
                                remember to update front-end js code as well.

        :type body: dict/Context, default value: {}
        :param body: other necessary information, e.g.: 'content'(notice's content), 'link'(notice's link), other keys for specfic uses

        :return: hackathon_notice in dict

        ::Example:
        :create_hackathon_notice(2, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy, {'content': 'zz'})
            a new notice for a hackathon with id 2 is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content is 'zz' and its link url is ''

        :create_hackathon_notice(-1, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy)
            a new notice not belongs to any hackathon is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content and link url is ''
        """
        hackathon_notice = HackathonNotice(content='',
                                           link='',
                                           event=notice_event,
                                           category=notice_category)

        hackathon = self.get_hackathon_by_id(hackathon_id)
        if hackathon:
            hackathon_notice.hackathon = hackathon

        # notice creation logic for different notice_events
        if hackathon:
            if notice_event == HACK_NOTICE_EVENT.HACK_CREATE:
                hackathon_notice.content = u"%s即将火爆来袭,敬请期待!" % (hackathon.display_name)
            # elif notice_event == HACK_NOTICE_EVENT.HACK_EDIT and hackathon:
            #     hackathon_notice.content = u"%s更新啦,快去看看!" % (hackathon.display_name)
            elif notice_event == HACK_NOTICE_EVENT.HACK_ONLINE:
                hackathon_notice.content = u"%s开始啦,点击报名!" % (hackathon.display_name)
                hackathon_notice.link = "/site/%s" % hackathon.name
            elif notice_event == HACK_NOTICE_EVENT.HACK_OFFLINE:
                hackathon_notice.content = u"%s圆满结束,点击查看详情!" % (hackathon.display_name)
                hackathon_notice.link = "/site/%s" % hackathon.name
            elif notice_event == HACK_NOTICE_EVENT.HACK_PLAN and body.get('receiver', None):
                user = body.get('receiver')
                old_hackathon_notice = HackathonNotice.objects(receiver=user, event=HACK_NOTICE_EVENT.HACK_PLAN,
                                                               hackathon=hackathon).first()
                if old_hackathon_notice:  # duplicate
                    return old_hackathon_notice.dic()

                hackathon_notice.content = u"您有未完成的任务,请提交开发说明书"
                hackathon_notice.receiver = user
                hackathon_notice.link = u"/site/%s/team" % (hackathon.name)

            elif notice_event == HACK_NOTICE_EVENT.HACK_REGISTER_AZURE and body.get('receiver', None):
                user = body.get('receiver')
                old_hackathon_notice = HackathonNotice.objects(receiver=user,
                                                               event=HACK_NOTICE_EVENT.HACK_REGISTER_AZURE,
                                                               hackathon=hackathon).first()
                if old_hackathon_notice:  # duplicate
                    return old_hackathon_notice.dic()

                hackathon_notice.content = u"请完成实名认证"
                hackathon_notice.receiver = user
                hackathon_notice.link = u"https://www.azure.cn/pricing/1rmb-trial-full/?form-type=waitinglist"
            else:
                pass

        if notice_event == HACK_NOTICE_EVENT.EXPR_JOIN and body.get('user_id'):
            user_id = body.get('user_id')
            user = self.user_manager.get_user_by_id(user_id)
            hackathon_notice.content = u"用户 %s 开始编程" % (user.nickname)
        else:
            pass

        # use assigned value if content or link is assigned in body
        hackathon_notice.content = body.get('content', hackathon_notice.content)
        hackathon_notice.link = body.get('link', hackathon_notice.link)

        hackathon_notice.save(validate=False)

        self.log.debug("a new notice is created: hackathon: %s, event: %d, category: %d" % (
            hackathon.name, notice_event, notice_category))
        return hackathon_notice.dic()
Ejemplo n.º 11
0
    def get_hackathon_notice(self, notice_id):
        hackathon_notice = HackathonNotice.objects(id=notice_id).first()
        if not hackathon_notice:
            return not_found("hackathon_notice not found")

        return hackathon_notice.dic()
Ejemplo n.º 12
0
    def get_hackathon_notice_list(self, body):
        """
        list hackathon notices, notices are paginated, can be filtered by hackathon_name, event and category,
        can be ordered by update_time, event and category.

        :type body: Context
        :param body: valid key/values(all key/values are optional)
            body = {
                hackathon_name: string,                  // filter by hackathon_name, default unfiltered
                filter_by_user: '******' | 'all',         // filter by user, default filter all notice that has specfic receivers
                category: 'int[,int...]',                // filter by category, default unfiltered
                event: 'int[,int...]',                   // filter by event, default unfiltered
                order_by: 'time' | 'event' | 'category', // order by update_time, event, category, default by time
                page: int,                               // page number after pagination, start from 1, default 1
                per_page: int                            // items per page, default 1000
            }

        :return: json style text, see util.Utility

        ::Example:
        : body = { order_by: 'time', category: '1,2,3', page: 1, per_page: 6 }
            search first 6 notices ordered by time, filtered by: category in [1,2,3]
        : body = { hackathon_name: 'hackathon', event: '1', order_by: 'event' }
            search first 1000 notices ordered by event, filtered by event == 1 and hackathon_name == 'hackathon'
        """

        hackathon_name = body.get("hackathon_name")
        filter_by_user = body.get("filter_by_user", "")
        notice_category = body.get("category")
        notice_event = body.get("event")
        order_by = body.get("order_by", "time")
        page = int(body.get("page", 1))
        per_page = int(body.get("per_page", 1000))

        hackathon_filter = Q()
        category_filter = Q()
        event_filter = Q()
        user_filter = Q(receiver=None)
        is_read_filter = Q()
        order_by_condition = '-update_time'

        if hackathon_name:  #list notices that belong to specfic hackathon
            hackathon = Hackathon.objects(
                name=hackathon_name).only('name').first()
            if hackathon:
                hackathon_filter = Q(hackathon=hackathon)
            else:
                return not_found('hackathon_name not found')
        else:  #only list online hackathons' notices or notices that not belong to any hackathon
            online_hackathon = Hackathon.objects(status=HACK_STATUS.ONLINE)
            hackathon_filter = Q(hackathon__in=online_hackathon) | Q(
                hackathon=None)

        if filter_by_user:  # only return notices that are sent to the login user
            user = None
            if self.user_manager.validate_login():
                user = g.user
                user_filter = Q(receiver=user)
                if filter_by_user == 'unread':
                    is_read_filter = Q(is_read=False)
            else:
                return bad_request("please login first")

        if notice_category:
            notice_category_tuple = tuple(
                [int(category) for category in notice_category.split(',')])
            category_filter = Q(category__in=notice_category_tuple)
        if notice_event:
            notice_event_tuple = tuple(
                [int(event) for event in notice_event.split(',')])
            event_filter = Q(event__in=notice_event_tuple)

        if order_by == 'category':
            order_by_condition = '+category'
        elif order_by == 'event':
            order_by_condition = '+event'
        else:
            order_by_condition = '-update_time'

        pagination = HackathonNotice.objects(
            hackathon_filter & category_filter & event_filter & user_filter
            & is_read_filter).order_by(order_by_condition).paginate(
                page, per_page)

        def func(hackathon_notice):
            return hackathon_notice.dic()

        # return serializable items as well as total count
        return self.util.paginate(pagination, func)
Ejemplo n.º 13
0
    def create_hackathon_notice(self,
                                hackathon_id,
                                notice_event,
                                notice_category,
                                body={}):
        """
        create hackathon notice with hackathon_id, notice_event, notice_category.
        notice 'content' and 'link' can be included in body (optional)

        :type hackathon_id: int
        :param hackathon_id: id of hackathon that the notice belongs to (-1 if the notice doesn't belong to a specfic hackathon)

        :type notice_event: Class HACK_NOTICE_EVENT
        :param notice_event: event that the notice is triggered by, used for notice filtering (see get_hackathon_notice_list())
                             more specfic than notice_category, new events can be added without disturbing front-end code

        :type notice_category: Class HACK_NOTICE_CATEGORY
        :param notice_category: category that the notice belongs to, used for notice filtering and notice properties display
                                at front-end (e.g. icons/descriptions, see oh.manage.notice.js & oh.site.hackathon.js),
                                more general than notice_event, if you want to add a new category in HACK_NOTICE_CATEGORY,
                                remember to update front-end js code as well.

        :type body: dict/Context, default value: {}
        :param body: other necessary information, e.g.: 'content'(notice's content), 'link'(notice's link), other keys for specfic uses

        :return: hackathon_notice in dict

        ::Example:
        :create_hackathon_notice(2, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy, {'content': 'zz'})
            a new notice for a hackathon with id 2 is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content is 'zz' and its link url is ''

        :create_hackathon_notice(-1, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy)
            a new notice not belongs to any hackathon is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content and link url is ''
        """
        hackathon_notice = HackathonNotice(content='',
                                           link='',
                                           event=notice_event,
                                           category=notice_category)

        hackathon = self.get_hackathon_by_id(hackathon_id)
        if hackathon:
            hackathon_notice.hackathon = hackathon

        # notice creation logic for different notice_events
        if hackathon:
            if notice_event == HACK_NOTICE_EVENT.HACK_CREATE:
                hackathon_notice.content = u"%s即将火爆来袭,敬请期待!" % (
                    hackathon.display_name)
            # elif notice_event == HACK_NOTICE_EVENT.HACK_EDIT and hackathon:
            #     hackathon_notice.content = u"%s更新啦,快去看看!" % (hackathon.display_name)
            elif notice_event == HACK_NOTICE_EVENT.HACK_ONLINE:
                hackathon_notice.content = u"%s开始啦,点击报名!" % (
                    hackathon.display_name)
                hackathon_notice.link = "/site/%s" % hackathon.name
            elif notice_event == HACK_NOTICE_EVENT.HACK_OFFLINE:
                hackathon_notice.content = u"%s圆满结束,点击查看详情!" % (
                    hackathon.display_name)
                hackathon_notice.link = "/site/%s" % hackathon.name
            elif notice_event == HACK_NOTICE_EVENT.HACK_PLAN and body.get(
                    'receiver', None):
                user = body.get('receiver')
                old_hackathon_notice = HackathonNotice.objects(
                    receiver=user,
                    event=HACK_NOTICE_EVENT.HACK_PLAN,
                    hackathon=hackathon).first()
                if old_hackathon_notice:  # duplicate
                    return old_hackathon_notice.dic()

                hackathon_notice.content = u"您有未完成的任务,请提交开发说明书"
                hackathon_notice.receiver = user
                hackathon_notice.link = u"/site/%s/team" % (hackathon.name)
            else:
                pass

        if notice_event == HACK_NOTICE_EVENT.EXPR_JOIN and body.get('user_id'):
            user_id = body.get('user_id')
            user = self.user_manager.get_user_by_id(user_id)
            hackathon_notice.content = u"用户 %s 开始编程" % (user.nickname)
        else:
            pass

        # use assigned value if content or link is assigned in body
        hackathon_notice.content = body.get('content',
                                            hackathon_notice.content)
        hackathon_notice.link = body.get('link', hackathon_notice.link)

        hackathon_notice.save(validate=False)

        self.log.debug(
            "a new notice is created: hackathon: %s, event: %d, category: %d" %
            (hackathon.name, notice_event, notice_category))
        return hackathon_notice.dic()
Ejemplo n.º 14
0
    def get_hackathon_notice(self, notice_id):
        hackathon_notice = HackathonNotice.objects(id=notice_id).first()
        if not hackathon_notice:
            return not_found("hackathon_notice not found")

        return hackathon_notice.dic()
Ejemplo n.º 15
0
    def get_hackathon_notice_list(self, body):
        """
        list hackathon notices, notices are paginated, can be filtered by hackathon_name, event and category,
        can be ordered by update_time, event and category.

        :type body: Context
        :param body: valid key/values(all key/values are optional)
            body = {
                hackathon_name: string,                  // filter by hackathon_name, default unfiltered
                category: 'int[,int...]',                // filter by category, default unfiltered
                event: 'int[,int...]',                   // filter by event, default unfiltered
                order_by: 'time' | 'event' | 'category', // order by update_time, event, category, default by time
                page: int,                               // page number after pagination, start from 1, default 1
                per_page: int                            // items per page, default 1000
            }

        :return: json style text, see util.Utility

        ::Example:
        : body = { order_by: 'time', category: '1,2,3', page: 1, per_page: 6 }
            search first 6 notices ordered by time, filtered by: category in [1,2,3]
        : body = { hackathon_name: 'hackathon', event: '1', order_by: 'event' }
            search first 1000 notices ordered by event, filtered by event == 1 and hackathon_name == 'hackathon'
        """

        hackathon_name = body.get("hackathon_name")
        notice_category = body.get("category")
        notice_event = body.get("event")
        order_by = body.get("order_by", "time")
        page = int(body.get("page", 1))
        per_page = int(body.get("per_page", 1000))

        hackathon_filter = Q()
        category_filter = Q()
        event_filter = Q()
        order_by_condition = '-update_time'

        if hackathon_name:
            hackathon = Hackathon.objects(name=hackathon_name).only('name').first()
            if hackathon:
                hackathon_filter = Q(hackathon=hackathon)
            else:
                return not_found('hackathon_name not found')

        if notice_category:
            notice_category_tuple = tuple([int(category) for category in notice_category.split(',')])
            category_filter = Q(category__in=notice_category_tuple)
        if notice_event:
            notice_event_tuple = tuple([int(event) for event in notice_event.split(',')])
            event_filter = Q(event__in=notice_event_tuple)

        if order_by == 'category':
            order_by_condition = '+category'
        elif order_by == 'event':
            order_by_condition = '+event'
        else:
            order_by_condition = '-update_time'

        pagination = HackathonNotice.objects(
            hackathon_filter & category_filter & event_filter
        ).order_by(
            order_by_condition
        ).paginate(page, per_page)

        def func(hackathon_notice):
            return hackathon_notice.dic()

        # return serializable items as well as total count
        return self.util.paginate(pagination, func)
Ejemplo n.º 16
0
    def create_hackathon_notice(self, hackathon_id, notice_event, notice_category, body={}):
        """
        create hackathon notice with hackathon_id, notice_event, notice_category.
        notice 'content' and 'link' can be included in body (optional)

        :type hackathon_id: int
        :param hackathon_id: id of hackathon that the notice belongs to (-1 if the notice doesn't belong to a specfic hackathon)

        :type notice_event: Class HACK_NOTICE_EVENT
        :param notice_event: event that the notice is triggered by, used for notice filtering (see get_hackathon_notice_list())
                             more specfic than notice_category, new events can be added without disturbing front-end code

        :type notice_category: Class HACK_NOTICE_CATEGORY
        :param notice_category: category that the notice belongs to, used for notice filtering and notice properties display
                                at front-end (e.g. icons/descriptions, see oh.manage.notice.js & oh.site.hackathon.js),
                                more general than notice_event, if you want to add a new category in HACK_NOTICE_CATEGORY,
                                remember to update front-end js code as well.

        :type body: dict/Context, default value: {}
        :param body: other necessary information, e.g.: 'content'(notice's content), 'link'(notice's link), other keys for specfic uses

        :return: hackathon_notice in dict

        ::Example:
        :create_hackathon_notice(2, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy, {'content': 'zz'})
            a new notice for a hackathon with id 2 is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content is 'zz' and its link url is ''

        :create_hackathon_notice(-1, HACK_NOTICE_EVENT.xx, HACK_NOTICE_CATEGORY.yy)
            a new notice not belongs to any hackathon is created for the propose of HACK_NOTICE_EVENT.xx. The notice's front-end icon
            and description is determined by HACK_NOTICE_CATEGORY.yy, while its content and link url is ''
        """
        hackathon_notice = HackathonNotice(content='',
                                           link='',
                                           event=notice_event,
                                           category=notice_category)

        hackathon = self.get_hackathon_by_id(hackathon_id)
        if hackathon:
            hackathon_notice.hackathon = hackathon

        # notice creation logic for different notice_events
        if hackathon:
            if notice_event == HACK_NOTICE_EVENT.HACK_CREATE:
                hackathon_notice.content = u"Hachathon: %s 创建成功" % (hackathon.name)
            elif notice_event == HACK_NOTICE_EVENT.HACK_EDIT and hackathon:
                hackathon_notice.content = u"Hachathon: %s 信息变更" % (hackathon.name)
            elif notice_event == HACK_NOTICE_EVENT.HACK_ONLINE and hackathon:
                hackathon_notice.content = u"Hachathon: %s 正式上线" % (hackathon.name)
            elif notice_event == HACK_NOTICE_EVENT.HACK_OFFLINE and hackathon:
                hackathon_notice.content = u"Hachathon: %s 下线" % (hackathon.name)
            else:
                pass

        if notice_event == HACK_NOTICE_EVENT.EXPR_JOIN and body.get('user_id'):
            user_id = body.get('user_id')
            user = self.user_manager.get_user_by_id(user_id)
            hackathon_notice.content = u"用户 %s 开始编程" % (user.nickname)
        else:
            pass

        # use assigned value if content or link is assigned in body
        hackathon_notice.content = body.get('content', hackathon_notice.content)
        hackathon_notice.link = body.get('link', hackathon_notice.link)

        hackathon_notice.save(validate=False)

        self.log.debug("a new notice is created: hackathon: %s, event: %d, category: %d" % (
            hackathon.name, notice_event, notice_category))
        return hackathon_notice.dic()