class ArticleAdminOperateLog(Document): article_id = StringField() operator_id = StringField() operate_type = IntField() operate_at = DateTimeField() operator_email = StringField() media_id = StringField() limit_post_times = IntField() @classmethod def generate_log(cls, request, article_id, operate_type, media_id=None, limit_post_times=None): now = datetime.datetime.utcnow() if media_id: media_id = str(media_id) ArticleAdminOperateLog.objects.create( article_id=article_id, operator_id=str(request.user.id), operate_type=operate_type, operate_at=now, operator_email=request.user.email, media_id=media_id, limit_post_times=limit_post_times)
class DailyMpBenefit(Document): lang = StringField() date = StringField() site_url = StringField() revenue = FloatField() checked_revenue = FloatField() checking_status = IntField()
class MediaPromotionLog(Document): media_id = StringField() father_media_id = StringField() promotion_code = StringField() get_bonus = BooleanField() get_bonus_at = DateTimeField() bonus_amount = FloatField() start_at = DateTimeField() is_banned = BooleanField() modified_at = DateTimeField() @classmethod def gen_promotion_log(cls, media_id, father_media_id, promotion_code): now = datetime.datetime.utcnow() try: mpl = cls.objects.create(media_id=str(media_id), father_media_id=father_media_id, promotion_code=promotion_code, get_bonus=False, bonus_amount=MEDIA_PROMOTION_BONUS_AMOUNT, start_at=now, is_banned=False, modified_at=now) except NotUniqueError: raise MediaPromotionCreateFail
class Bonus(Document): amount = FloatField() type = IntField() reason = StringField() create_at = DateTimeField() operator_id = StringField() operator_email = StringField() media_id = StringField()
class CommentMediaInfo(Document): media_id = StringField() media_title = StringField() sync_time = DateTimeField() unread_comment_count = IntField() usable = BooleanField() synced_langs = ListField(StringField()) last_comment_tag_mapping = DictField()
class Announcement(Document): title = StringField() content = StringField() published_at = DateTimeField() modified_at = DateTimeField() user_id = StringField() user_email = StringField() status = IntField() type = IntField()
class DailyArticle(Document): date = StringField() online_seq_id = IntField() lang = StringField() rec_count = IntField() read_count = IntField() uclick_count = IntField() # user unique read count share_count = IntField() comment_count = IntField() favorite_count = IntField()
class WithDraw(Document): user_id = StringField() media_id = StringField() amount = FloatField() payment_info = DictField() create_at = DateTimeField() status = IntField() operator_id = StringField() operator_email = StringField() operate_at = DateTimeField()
class DailyMpArticleBenefit(Document): date = StringField() lang = StringField() online_seq_id = IntField() category = StringField() site_url = StringField() uclick = StringField() share_percent = FloatField() revenue_rate = FloatField() unit_price = FloatField() revenue = FloatField() checking_status = IntField()
class DailyMedia(Document): lang = StringField() date = StringField() rec_count = IntField() read_count = IntField() uclick_count = IntField() share_count = IntField() comment_count = IntField() mp_fans_count = IntField() new_count = IntField() site_url = StringField() live_article_count = IntField() extra_rec_count = IntField() extra_read_count = IntField() extra_uclick_count = IntField()
class Notification(Document): media_id = StringField() status = IntField() content = StringField() type = IntField() published_at = DateTimeField() @classmethod def create_notification(cls, media_id, n_type, content): now = datetime.datetime.utcnow() notification = cls.objects.create(status=STATUS_UNREAD, type=n_type, content=content, media_id=media_id, published_at=now) return notification
class RealTimeArticle(Document): online_seq_id = IntField() lang = StringField() rec_count = IntField() read_count = IntField() share_count = IntField() comment_count = IntField() favorite_count = IntField()
class MediaAdminOperateLog(Document): media_id = StringField() operator_id = StringField() operate_type = IntField() operate_at = DateTimeField() operate_content = StringField() operator_email = StringField() @classmethod def generate_log(cls, request, media_id, operate_type, operate_content): now = datetime.datetime.utcnow() MediaAdminOperateLog.objects.create(media_id=media_id, operator_id=str(request.user.id), operate_type=operate_type, operate_at=now, operate_content=operate_content, operator_email=request.user.email)
class PartnerToken(Document): partner_key = StringField() partner_secret = StringField() domain = StringField() site_name = StringField() @classmethod def generate_token(cls, domain, site_name): token = cls.objects(domain=domain).first() if not token: m = md5(domain) partner_key = m.hexdigest() m = md5(site_name) partner_secret = m.hexdigest() token = cls.objects.create(domain=domain, site_name=site_name, partner_key=partner_key, partner_secret=partner_secret) return {'secret': token.partner_secret, 'key': token.partner_key}
class Image(Document): media_id = StringField() # image_type = StringField() width = IntField() height = IntField() origin = StringField() thumb = StringField() thumb_width = IntField() thumb_height = IntField() headline = StringField() headline_width = IntField() headline_height = IntField() usable = BooleanField() source = StringField() type = StringField() thumb_jpg = StringField() origin_jpg = StringField() headline_jpg = StringField()
class SyncHistory(Document): date = StringField() meta = { 'indexes': [ { 'fields': ['date'], 'unique': True, }, ] } @classmethod def get_latest_sync_date(cls): sh = cls.objects.order_by('-id').first() if not sh: return None return sh.date
class WeeklyMediaIncome(Document): start_date = StringField() end_date = StringField() revenue = FloatField() site_url = StringField()
class User(MongoEngineUser): user_type = StringField() email_verified = BooleanField() USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['user_type'] @classmethod def gen_email_username(cls, email): return 'm_%s' % email def has_password(self): if not self.user_type == 'email' and self.email is None: return False return True @classmethod def check_joined(cls, username): u = cls.objects(username=username).only('id').first() if not u: return False return True def load_user_profile(self): up = UserProfile.objects(user_id=str(self.id)).first() if not up: return None self._up = up return up def create_user_profile(self, **kwargs): up = self.get_user_profile() if up is None: up = UserProfile(user_id=str(self.id)) for key, value in kwargs.iteritems(): setattr(up, key, value) up.save() def get_user_profile(self): up = getattr(self, '_user_profile', None) if up: return up up = self.load_user_profile() setattr(self, '_user_profile', up) return up @classmethod def get_user_by_email(cls, email): user_name = User.gen_email_username(email) user = cls.objects(username=user_name).first() return user def update_user_profile(self, **kwargs): up = self.get_user_profile() for key, value in kwargs.iteritems(): setattr(up, key, value) up.save() def get_related_media_account(self, god_view=False, mid=None): media_account = getattr(self, '_media_account', None) if media_account: return media_account from media.models import MediaAccount if god_view and mid: media_account = MediaAccount.objects.with_id(mid) else: media_account = MediaAccount.objects(user_id=str(self.id)).first() setattr(self, '_media_account', media_account) return media_account def is_email_user(self): return self.user_type == 'email' @property def media_account(self): return self.get_related_media_account() @property def comment_permission(self): media = self.get_related_media_account() from comments.models import CommentMediaInfo comment_media = CommentMediaInfo.objects( media_id=str(media.id)).first() if comment_media and comment_media.usable: return True return False @property def account_name(self): media_account = self.get_related_media_account() if not media_account: if self.is_email_user(): return self.email else: up = self.get_user_profile() if not up: return None return up.accounts.get('fb', {}).get('name') return media_account.title @property def account_icon(self): media_account = self.get_related_media_account() if not media_account: return '' return media_account.icon def has_permission(self, request_path): if self.is_superuser: return True normalized_request_path = request_path.replace('/admin/', '').split('/')[0] normalized_request_path = '/admin/%s/' % normalized_request_path return normalized_request_path in self.permissions_list @property def permissions_list(self): up = self.get_user_profile() return up.permissions def set_permission(self, urls): self.update_user_profile(permissions=urls)
class PancardBlackList(Document): user_pan_no = StringField()
class RevenuePercent(Document): lang = StringField() category = StringField() revenue_rate = FloatField()
class DailyTotalRevenue(Document): date = StringField() total_revenue = FloatField()
class MediaPromotionUser(Document): media_id = StringField() media_join_at = DateTimeField() banned_at = StringField() status = IntField() promotion_code = StringField() time_reached = BooleanField() read_reached = BooleanField() no_banned = BooleanField() @classmethod def gen_pcode(cls): pcode = None for x in xrange(3): code = cls.gen_promotion_code() mpc = cls.objects(promotion_code=code).first() if mpc: continue pcode = code break return pcode @classmethod def gen_promotion_code(cls): chars = [] for x in xrange(6): chars.append(random.choice(PROMOTION_CODE_CAND)) return ''.join(chars) @classmethod def gen_promotion_user(cls, media_id): now = datetime.datetime.utcnow() pcode = cls.gen_pcode() mpu = cls.objects.create(media_id=media_id, media_join_at=now, status=MEDIA_PROMOTION_NEWBIE_STATUS, promotion_code=pcode, time_reached=False, read_reached=False, no_banned=True) return mpu def banned_promotion_user(self): if self.status == MEDIA_PROMOTION_NORMAL_STATUS: media = MediaAccount.objects.with_id(self.media_id) notify_utils.create_media_promotion_notification( media, MEDIA_PROMOTION_NOTIFICATION_BANNED_TYPE) self.status = MEDIA_PROMOTION_BANNED_STATUS now = str(datetime.datetime.utcnow().date()) self.banned_at = now self.no_banned = False self.save() mpls = MediaPromotionLog.objects(get_bonus=False, father_media_id=self.media_id) mpls.update(set__is_banned=True, set__modified_at=now) def judge_to_normal(self): return self.time_reached and self.read_reached and self.no_banned @classmethod def get_pcode_owner_media(cls, pcode): mpu = cls.objects(promotion_code=pcode).first() if not mpu: raise MediaPcodeNotExist if mpu.status != MEDIA_PROMOTION_NORMAL_STATUS: raise MediaPcodeNotAllowable return mpu
class MediaAccount(Document): verified_status = IntField() info_update = BooleanField() lang_synced_status_mapping = DictField() title = StringField() unformatted_title = StringField() description = StringField() icon = StringField() new_title = StringField() new_description = StringField() new_icon = StringField() user_id = StringField() user_pan_no = StringField() user_real_name = StringField() user_email = StringField() user_phone = StringField() user_location_address = StringField() user_location_city = StringField() user_location_state = StringField() user_pin_code = StringField() last_modified_at = DateTimeField() checked_at = DateTimeField() updated_at = DateTimeField() create_at = DateTimeField() checker_email = StringField() updated_email = StringField() check_reason = StringField() valid_duration = IntField() share_percent = IntField() total_revenue = FloatField() revenue_update_date = StringField() total_withdraw = FloatField() payment_info = DictField() daily_submit_limit = IntField() limit_end_at = DateTimeField() limit_reason = StringField() suspend_reason = StringField() # NOTE: india time zone grade = IntField() remark = StringField() is_internship = BooleanField() @classmethod def check_pan_no_reach_limit(cls, user_pan_no): count = cls.objects(user_pan_no=user_pan_no).count() if count >= 3: return True return False @classmethod def check_pan_no_is_black(cls, user_pan_no): black_pan_no = PancardBlackList.objects(user_pan_no=user_pan_no) return bool(black_pan_no) def withdraw_stat(self): total_revenue, total_withdraw, total_balance = MediaAccount.calc_balance( self.total_revenue or 0, self.total_withdraw or 0) return dict(total_revenue=('%.2f' % total_revenue), total_withdraw=('%.2f' % total_withdraw), total_balance=('%.2f' % total_balance)) @classmethod def calc_balance(cls, revenue, withdraw): def decimal_floor(num): # 小数向下取整函数 ret = (math.floor(num * 100)) / 100.0 if ret > num: # 避免极端情况,产生的数据错误 return ret - 0.01 return ret def decimal_ceil(num): # 小数向上取整函数 ret = (math.ceil(num * 100)) / 100.0 if ret < num: return ret + 0.01 return ret if revenue - withdraw > 1: # 在两个数距离较大的时候,被减数向下取整,减数向上取整 _revenue = decimal_floor(revenue) _withdraw = decimal_floor(withdraw) if _withdraw != withdraw: # 避免withdraw为零的时候,出现0.01的情况,造成用户感知明显 _withdraw += 0.01 else: # 在两个数距离较小时,被减数和减数都向下取整,避免减数大于被减数的情况出现 _revenue = decimal_floor(revenue) _withdraw = int(withdraw * 100) / 100.0 _balance = (_revenue - _withdraw) return _revenue, _withdraw, decimal_floor(_balance) def can_auto_pass(self): if self.grade == MEDIA_GRADE_A: return not 5 == random.randint(0, 9) if self.grade == MEDIA_GRADE_P: return not 1 == random.randint(0, 1) return False def judge_pass_internship(self): pass_article_count = Article.objects(media_id=str(self.id), status=STATUS_PUBLISHED).count() return pass_article_count >= (MEDIA_INTERNSHIP_ARTICLE_NUM - 1) def limit_media(self, request, limit_days, daily_limit, limit_reason): limit_end_time = time_utils.get_india_now() + datetime.timedelta( int(limit_days)) self.limit_end_at = datetime.datetime(limit_end_time.year, limit_end_time.month, limit_end_time.day) self.limit_reason = limit_reason self.daily_submit_limit = daily_limit self.save() notify_utils.create_media_limit_notification(self) content = MEDIA_AMDIN_OPERATE_LIMIT_POST_CONTENT_TEMPL % (daily_limit, limit_days) MediaAdminOperateLog.generate_log(request, str(self.id), MEDIA_AMDIN_OPERATE_TYPE_LIMIT_POST, content) mpu = MediaPromotionUser.objects(media_id=str(self.id)).first() mpu.banned_promotion_user() @property def verify_passed(self): return self.verified_status == VERIFY_STATUS_PASSED @property def verify_failed(self): return self.verified_status == VERIFY_STATUS_FAILED @property def verify_submitted(self): return self.verified_status == VERIFY_STATUS_SUBMITTED @property def verify_suspend(self): return self.verified_status == VERIFY_STATUS_SUSPEND @property def site_url(self): return media_utils.gen_site_url(self.id) @classmethod def gen_unformatted_title(cls, title): unformatted_title = title.strip().lower() return MULTI_SPACES_PATTERN.sub(' ', unformatted_title) def add_submit_log(self, article_id): try: MediaSubmitArticleLog.objects.create( media_id=str(self.id), article_id=article_id, date=str(time_utils.get_india_now().date())) except NotUniqueError: return @property def is_under_limit(self): if not self.limit_end_at: return False now = time_utils.get_india_now() if now > self.limit_end_at: return False return True @property def under_limit_date(self): if not self.is_under_limit: return if not self.limit_end_at: return None return self.limit_end_at.strftime('%Y-%m-%d %H:%M') def check_reached_submit_limit(self): if not self.is_under_limit: return False daily_submit_count = MediaSubmitArticleLog.objects( media_id=str(self.id), date=str(time_utils.get_india_now().date())).count() return daily_submit_count >= self.daily_submit_limit def check_internship_submit_limit(self, article_id=None): if not self.is_internship: return False if article_id: article_submit_count = MediaSubmitArticleLog.objects( media_id=str(self.id), article_id=str(article_id)).count() if article_submit_count > 0: return False daily_submit_count = MediaSubmitArticleLog.objects( media_id=str(self.id), date=str(time_utils.get_india_now().date())).count() return daily_submit_count >= self.daily_submit_limit def withdraw_in_processing(self): count = WithDraw.objects(media_id=str(self.id), status=WD_STATUS_SUMBMITTED).count() return not count == 0 def has_paytm(self): return self.payment_info and 'paytm_account' in self.payment_info
class RealTimeMedia(Document): lang = StringField() site_url = StringField() follow_count = IntField() read_count = IntField()
class UserProfile(Document): user_id = StringField() accounts = DictField() permissions = ListField(StringField())
class MediaSubmitArticleLog(Document): media_id = StringField() article_id = StringField() date = StringField()
class Article(Document): media_id = StringField() title = StringField() content = StringField() top_images = ListField(DictField()) related_images = ListField(DictField()) youtube_video_ids = ListField(StringField()) online_url = StringField() online_seq_id = IntField() cover_type = IntField() words_count = IntField() status = IntField() category = StringField() keywords = ListField(StringField()) language = StringField() published_at = DateTimeField() last_modified_at = DateTimeField() submited_at = DateTimeField() takedown_at = DateTimeField() deleted_at = DateTimeField() last_op_at = DateTimeField() checked_at = DateTimeField() checker_email = StringField() checker = StringField() check_reason = StringField() check_reason_type = IntField() submit_times = IntField() revision = BooleanField() porn_score = IntField() @property def source_url(self): return 'mpa_%s' % str(self.id) def get_media(self): m = getattr(self, '_media', None) if m: return m from media.models import MediaAccount m = MediaAccount.objects.with_id(self.media_id) self._media = m return m def gen_online_url(self): if not self.online_url: return None domain = LANG_DOMAIN_MAPPING.get(self.language) if not domain: domain = 'newsdog.today' return 'http://%s%s' % (domain, self.online_url) def check_reached_submit_limit(self): return self.submit_times >= ARTICLE_SUBMIT_LIMIT