예제 #1
0
 def setUp(self):
     super(TestUserSearch, self).setUp()
     self.es_connection = ESConnection("localhost", 9200, self.io_loop)
     self.us = ESSearch(index_mapping=user_index_mapping,
                        index_name="index",
                        type_name="user",
                        analyze_fields=user_analyze_fields,
                        none_analyze_fields=user_none_analyze_fields,
                        io_loop=self.io_loop)
     self.io_loop.run_sync(self.setup_coro)
예제 #2
0
def fix_QA_search():
    db = mongoclient.fbt
    cnt = 0
    question_searcher = ESSearch(host=ES_HOST, port=ES_PORT,
                               index_name="question_index",
                               type_name="question",
                               analyze_fields=question_analyze_fields,
                               none_analyze_fields=question_none_analyze_fields,
                               index_mapping=question_index_mapping)
    for question in db.questions.find().batch_size(30):
        print question["title"], " is indexing...."
        yield question_searcher.insert(question["id"], question)
        cnt += 1
    print "all cnt:", cnt
예제 #3
0
def fix_QA_search():
    db = mongoclient.fbt
    cnt = 0
    question_searcher = ESSearch(
        host=ES_HOST,
        port=ES_PORT,
        index_name="question_index",
        type_name="question",
        analyze_fields=question_analyze_fields,
        none_analyze_fields=question_none_analyze_fields,
        index_mapping=question_index_mapping)
    for question in db.questions.find().batch_size(30):
        print question["title"], " is indexing...."
        yield question_searcher.insert(question["id"], question)
        cnt += 1
    print "all cnt:", cnt
예제 #4
0
def fix_resource_search():
    db = mongoclient.fbt
    cnt = 0
    resource_searcher = ESSearch(ES_HOST, port=ES_PORT,
                                 index_name="resource_index",
                                 type_name="resource",
                                 analyze_fields=resource_analyze_fields,
                                 none_analyze_fields=resource_none_analyze_fields,
                                 index_mapping=resource_index_mapping)
    udb = UniversityDB()
    for resourse in db.study_resources.find().batch_size(30):
        print resourse["filename"], " is indexing...."
        resourse["university_short_names"] = udb.get_short_name(resourse["university"])
        yield resource_searcher.insert(resourse["file_id"], resourse)
        cnt += 1
    print "all cnt:", cnt
예제 #5
0
def fix_course_search():
    db = mongoclient.fbt
    cnt = 0
    course_searcher = ESSearch(host=ES_HOST, port=ES_PORT,
                               index_name="course_index",
                               type_name="course",
                               analyze_fields=course_analyze_fields,
                               none_analyze_fields=course_none_analyze_fields,
                               index_mapping=course_index_mapping)
    udb = UniversityDB()
    for course in db.courses.find().batch_size(30):
        print course["course"], " is indexing...."
        course["university_short_names"] = udb.get_short_name(course["university"])
        yield course_searcher.insert(course["course_id"], course)
        cnt += 1
    print "all cnt:", cnt
예제 #6
0
def fix_user_search():
    db = mongoclient.fbt
    cnt = 0
    user_searcher = ESSearch(host=ES_HOST, port=ES_PORT,
                             index_name="user_index",
                             type_name="user",
                             none_analyze_fields=user_none_analyze_fields,
                             analyze_fields=user_analyze_fields,
                             index_mapping=user_index_mapping)
    udb = UniversityDB()
    for user in db.users.find().batch_size(30):
        if "university" in user and "college" in user and user["university"] and user["college"]:
            user["university_short_name"] = udb.get_short_name(user["university"])
            print user["university"], user["real_name"], " is indexing...."
            yield user_searcher.insert(user["uid"], user)
            cnt += 1
    print "all cnt:", cnt
예제 #7
0
def fix_course_search():
    db = mongoclient.fbt
    cnt = 0
    course_searcher = ESSearch(host=ES_HOST,
                               port=ES_PORT,
                               index_name="course_index",
                               type_name="course",
                               analyze_fields=course_analyze_fields,
                               none_analyze_fields=course_none_analyze_fields,
                               index_mapping=course_index_mapping)
    udb = UniversityDB()
    for course in db.courses.find().batch_size(30):
        print course["course"], " is indexing...."
        course["university_short_names"] = udb.get_short_name(
            course["university"])
        yield course_searcher.insert(course["course_id"], course)
        cnt += 1
    print "all cnt:", cnt
예제 #8
0
def fix_resource_search():
    db = mongoclient.fbt
    cnt = 0
    resource_searcher = ESSearch(
        ES_HOST,
        port=ES_PORT,
        index_name="resource_index",
        type_name="resource",
        analyze_fields=resource_analyze_fields,
        none_analyze_fields=resource_none_analyze_fields,
        index_mapping=resource_index_mapping)
    udb = UniversityDB()
    for resourse in db.study_resources.find().batch_size(30):
        print resourse["filename"], " is indexing...."
        resourse["university_short_names"] = udb.get_short_name(
            resourse["university"])
        yield resource_searcher.insert(resourse["file_id"], resourse)
        cnt += 1
    print "all cnt:", cnt
예제 #9
0
 def setUp(self):
     super(TestUserSearch, self).setUp()
     self.es_connection = ESConnection("localhost", 9200, self.io_loop)
     self.us = ESSearch(index_mapping=user_index_mapping,
                        index_name="index",
                        type_name="user",
                        analyze_fields=user_analyze_fields,
                        none_analyze_fields=user_none_analyze_fields,
                        io_loop=self.io_loop)
     self.io_loop.run_sync(self.setup_coro)
예제 #10
0
def fix_user_search():
    db = mongoclient.fbt
    cnt = 0
    user_searcher = ESSearch(host=ES_HOST,
                             port=ES_PORT,
                             index_name="user_index",
                             type_name="user",
                             none_analyze_fields=user_none_analyze_fields,
                             analyze_fields=user_analyze_fields,
                             index_mapping=user_index_mapping)
    udb = UniversityDB()
    for user in db.users.find().batch_size(30):
        if "university" in user and "college" in user and user[
                "university"] and user["college"]:
            user["university_short_name"] = udb.get_short_name(
                user["university"])
            print user["university"], user["real_name"], " is indexing...."
            yield user_searcher.insert(user["uid"], user)
            cnt += 1
    print "all cnt:", cnt
예제 #11
0
 def __init__(self, db=None, redis_cache=None, redis_db_man=None, es_host=None, es_port=None):
     self._db = db or motorclient.fbt
     self._redis_cache = redis_cache or Redis()
     super(UserManager, self).__init__(self._redis_cache)
     self._udb = UniversityDB()
     self.PREVIEW_FIELDS = {"user": 1, "uid": 1, "icon": 1, "password": 1,
         "tags": 1, "thumb_num": 1, "followers_num":1, "state": 1, "state_desc": 1,
         "honor": 1, "thanks_coin": 1, "real_name": 1, "desc": 1, "gender": 1,
         "answers_num":1, "nick_name": 1, 'university': 1, 'college': 1, "_id": 0}
     self._user_searcher = ESSearch(host=es_host or ES_HOST, port=es_port or ES_PORT,
                                    index_name="user_index",
                                    type_name="user",
                                    none_analyze_fields=user_none_analyze_fields,
                                    analyze_fields=user_analyze_fields,
                                    index_mapping=user_index_mapping)
     for _, v in STAR_CLASS.iteritems():
         self.PREVIEW_FIELDS[v] = 1
예제 #12
0
def run():
    mock_redis = redis.StrictRedis()
    sync_db = MongoClient()
    db = MotorClient()
    mock_mapping = {
        "settings": {
            "refresh_interval": "5s",
            "number_of_shards": 2,
            "number_of_replicas": 1
        },
        "mappings": {
            "_default_": {
                "_all": {
                    "enabled": False
                }
            },
        }
    }
    # CAUTION: local search disabled!!!
    es = ESSearch(host="localhost",
                  port=9200,
                  index_name="test_index",
                  type_name="test_type",
                  index_mapping=mock_mapping,
                  analyze_fields=[],
                  none_analyze_fields=[])
    with mock.patch('redis_handler.RedisHandler.redis_client',
                    return_value=mock_redis) as whate_ever:
        with mock.patch('redis_cluster_proxy.Redis',
                        return_value=mock_redis) as whate_ever1:
            with mock.patch("pymongo.MongoReplicaSetClient",
                            return_value=sync_db) as what_ever2:
                with mock.patch("motor.MotorReplicaSetClient",
                                return_value=db) as what_ever3:
                    with mock.patch("es_search.ESSearch",
                                    return_value=es) as what_ever4:
                        from fbt_http import main
                        main()
예제 #13
0
class UserManager(AbstractSearcher):
    _primary_db = motorclient.fbt_realtime
    _REDIS_CACHE_KEY_FOR_PASSWD = "user:passwd"
    _REDIS_SESSION_KEY_PREFIX = "session:"
    _REDIS_EXPERIENCE_TAG = "experience:tag:"
    _REDIS_USER_FOLLOWERS = "user:followers:"
    _REDIS_USER_TAG_LIST = "user:experience:tags:"
    _REDIS_USER_INFO = "user_info:"
    _REDIS_EXP_TAG_USERS = "experience:tag:users:"
    _DESCENDING = -1
    TWO_DAY = 2 * 24 * 3600  # TODO maybe this should be more long
    TWO_HOUR = 2 * 3600
    TWO_MINUTES = 120
    MAX_USER_CNT = 200
    TOP_STAR_USER_CNT = 100
    PAGE_NUM = 10

    register_info = {"SAME_PHONE": 3, "SAME_EMAIL": 2, "SAME_NICK": 1, "NOT_REGISTERED": 0}
    _redis_cache = Redis()

    def __init__(self, db=None, redis_cache=None, redis_db_man=None, es_host=None, es_port=None):
        self._db = db or motorclient.fbt
        self._redis_cache = redis_cache or Redis()
        super(UserManager, self).__init__(self._redis_cache)
        self._udb = UniversityDB()
        self.PREVIEW_FIELDS = {"user": 1, "uid": 1, "icon": 1, "password": 1,
            "tags": 1, "thumb_num": 1, "followers_num":1, "state": 1, "state_desc": 1,
            "honor": 1, "thanks_coin": 1, "real_name": 1, "desc": 1, "gender": 1,
            "answers_num":1, "nick_name": 1, 'university': 1, 'college': 1, "_id": 0}
        self._user_searcher = ESSearch(host=es_host or ES_HOST, port=es_port or ES_PORT,
                                       index_name="user_index",
                                       type_name="user",
                                       none_analyze_fields=user_none_analyze_fields,
                                       analyze_fields=user_analyze_fields,
                                       index_mapping=user_index_mapping)
        for _, v in STAR_CLASS.iteritems():
            self.PREVIEW_FIELDS[v] = 1
        # self._hot_board = HotBoard(self._db, ioloop.IOLoop.instance())

    @classmethod
    def set_db(cls, db):
        cls._primary_db = db

    @gen.coroutine
    def is_phone_registered(self, phone):
        db_user = yield self._db.users.find_one({"phone": phone}, {"phone": 1})
        if db_user:
            raise gen.Return(self.register_info["SAME_PHONE"])
        else:
            raise gen.Return(self.register_info["NOT_REGISTERED"])

    @gen.coroutine
    def register_user(self, user, passwd, user_icon_url, real_name, school, college, nick, gender, phone=None):
        uid = UserManager.generate_uid(user)
        new_user = {"uid": uid, 'user': user,'time':datetime.now().strftime('%Y-%m-%d %H:%M'), 'icon': user_icon_url,'desc': "",
            'real_name':real_name, 'phone': phone, 'qq':'', 'gender':gender, 'love_state':'', 'school':school, 'address':'',
            'university': school, 'college': college, 'password':UserManager.generate_salt_passwd(user, passwd), 'nick_name':nick, 'friends':[],
            'university_id': self._udb.get_university_id(school), "university_short_name": self._udb.get_short_name(school), 
            'index_ctime': long(time()),
        }

        yield self._db.users.insert(new_user)
        yield self._user_searcher.insert(uid, new_user)
        self.add_to_statistic(school, college, user)
        raise gen.Return(uid)

    def register_user_sync(self, user, passwd, user_icon_url, real_name, school, college, nick, gender, phone=None):
        uid = UserManager.generate_uid(user)
        new_user = {"uid": uid, 'user': user,'time':datetime.now().strftime('%Y-%m-%d %H:%M'), 'icon': user_icon_url,'desc': "",
            'real_name':real_name, 'phone': phone, 'qq':'', 'gender':gender, 'love_state':'', 'school':school, 'address':'',
            'university': school, 'college': college, 'password':UserManager.generate_salt_passwd(user, passwd), 'nick_name':nick, 'friends':[],
            'university_id': self._udb.get_university_id(school), "mocked": True, "university_short_name": self._udb.get_short_name(school)
        }
        db = mongoclient.fbt
        db.users.insert(new_user)
        self.add_to_statistic(school, college, user)
        return uid

    @gen.coroutine
    def user_chg_password(self, user, passwd):
        salted_passwd = UserManager.generate_salt_passwd(user, passwd)
        yield self._db.users.update({"user": user},{"$set":{"password": salted_passwd}})
        self.update_password_of_user_cache(user, salted_passwd)

    @classmethod
    @gen.coroutine
    def get_friend_list(cls, uid):
        assert uid > 0
        my = yield cls._primary_db.users.find_one({"uid": uid}, {"friends": 1})
        if my and "friends" in my:
            raise gen.Return([friend['uid'] for friend in my["friends"]])
        raise gen.Return([])

    @gen.coroutine
    def is_user_registered(self, email, nick_name):
        db_user = yield self._db.users.find_one({"user": email}, {"user": 1})
        if db_user:
            raise gen.Return(self.register_info["SAME_EMAIL"])
        db_user = yield self._db.users.find_one({"$or": [{"user": email}, {"nick_name": nick_name}]},
                                                       {"user": 1, "nick_name": 1})
        if db_user:
            if db_user["user"] == email:
                raise gen.Return(self.register_info["SAME_EMAIL"])
            else:
                raise gen.Return(self.register_info["SAME_NICK"])
        raise gen.Return(self.register_info["NOT_REGISTERED"])

    @gen.coroutine
    def is_email_registered(self, email):
        db_user = yield self._db.users.find_one({"user": email}, {"user": 1})
        if db_user:
            raise gen.Return(self.register_info["SAME_EMAIL"])
        else:
            raise gen.Return(self.register_info["NOT_REGISTERED"])

    @gen.coroutine
    def find_user_info(self, user, is_mine):
        filter_dict = {"uid": 1, "user": 1, "icon": 1, "real_name": 1, "password": 1, "thumb_num": 1, "tags": 1, "gender": 1,
                             "interested_tags": 1, 'university': 1, 'college': 1, "desc": 1, "birthday": 1, 'followers_num': 1,
                             "following_num": 1, "state": 1, "state_desc": 1, "honor": 1, "is_postgraduate_star": 1,
                             "is_certificate_star": 1, "is_USA_star": 1, "is_work_star": 1, "is_campus_star": 1, "is_internship_star": 1, "_id": 0}
        if is_mine:
            filter_dict.update({"qq": 1, "phone": 1})
        db_user = yield self._db.users.find_one({"user": user}, filter_dict)
        raise gen.Return(db_user)

    @gen.coroutine
    def find_user(self, user, preview=False):
        db_user = self.get_cached_user(user)
        if db_user is None:
            db_user = yield self._db.users.find_one({"user": user}, self.PREVIEW_FIELDS)
            if db_user:
                db_user["star_info"] = [v for k, v in STAR_CLASS.iteritems() if v in db_user]
                # TODO(bonelee.lzh) remove the code and put it other place
                coins_of_user = yield self._db.coins_of_user.find_one({"user": user}, {"coins_by_study": 1})
                if coins_of_user:
                    coins_by_study = coins_of_user.get('coins_by_study', 0)
                    if coins_by_study:
                        db_user['coins_by_study'] = int(coins_by_study)
                self.set_cached_user(user, db_user)
        if preview:
            if db_user and "password" in db_user:
                del db_user["password"]
        raise gen.Return(db_user)

    @gen.coroutine
    def find_user_by_nick(self, nick_name):
        db_user = yield self._db.users.find_one({"nick_name": nick_name}, self.PREVIEW_FIELDS)
        if db_user:
            self.set_cached_user(db_user["user"], db_user)
        raise gen.Return(db_user)


    @gen.coroutine
    def find_user_by_id(self, uid):
        db_user = yield self._db.users.find_one({"uid": uid},  self.PREVIEW_FIELDS)
        if db_user:
            self.set_cached_user(db_user["user"], db_user)
            if "password" in db_user:
                del db_user["password"]
        raise gen.Return(db_user)

    def set_cached_user(self, user, user_info, preview=False):
        if  preview:
            cached_key = self._REDIS_USER_INFO+"preview:"+user
        else:
            cached_key = self._REDIS_USER_INFO+user
        ONE_WEEK = 2 * 3600
        self._redis_cache.setex(cached_key, ONE_WEEK, json.dumps(user_info))

    def get_cached_user(self, user):
        cached_key = self._REDIS_USER_INFO+user
        cached_user = self._redis_cache.get(cached_key)
        if cached_user:
            db_user = json.loads(cached_user)
            return db_user
        else:
            return None

    def update_password_of_user_cache(self, user, new_passwd):
        user_info = self.get_cached_user(user)
        if user_info:
            user_info["password"] = new_passwd
            self.set_cached_user(user, user_info)

    @classmethod
    def generate_uid(cls, user):
        r = cls._generate_salt(user)
        tmp_uid = str(long(time())) + str(r)
        uid = long(tmp_uid)
        return uid

    @classmethod
    def generate_user_icon(cls):
        return str(random.randint(1, 36))

    @classmethod
    def _generate_salt(cls, user):
        random.seed(hash(user))
        r = random.randint(1, 10000)
        if r < 10:
            r = "000" + str(r)
        elif r < 100:
            r = "00" + str(r)
        elif r < 1000:
            r = "0" + str(r)
        return r

    @classmethod
    def generate_salt_passwd(cls, user, passwd):
        r = cls._generate_salt(user)
        return passwd + str(r)

    @gen.coroutine
    def change_college(self, user, university, college):
        self.add_to_statistic(university, college, user)
        updated_fields = {"university": university, "college": college, "university_short_name": self._udb.get_short_name(university),
                      "university_id": self._udb.get_university_id(university)}
        yield self._db.users.update({"user": user}, {"$set": updated_fields})
        db_user = self.get_cached_user(user)
        if db_user:
            yield self._user_searcher.update_multi_fields(db_user["uid"], updated_fields)
            db_user["university"] = university
            db_user["college"] = college
            self.set_cached_user(user, db_user)
            raise gen.Return(True)
        else:
            raise gen.Return(False)
    
    @gen.coroutine
    def set_star_user_info(self, user, university, college, degree, entrance_year, university_mail=None):
        db_user = self.get_cached_user(user)
        if db_user:
            db_user["university"] = university
            db_user["college"] = college
            db_user["entrance_year"] = entrance_year
            db_user["degree"] = degree
            db_user["university_mail"] = university_mail
            db_user["university_id"] = self._udb.get_university_id(university)
            self.set_cached_user(user, db_user)
        updated_fields = {"university": university, "college": college,
                           "university_id": self._udb.get_university_id(university),
                           "university_short_name": self._udb.get_short_name(university),
                           "degree": degree, "university_mail": university_mail, "entrance_year": entrance_year}
        user_info = yield self._db.users.find_and_modify({"user": user},
                                    {"$set": updated_fields})
        yield self._user_searcher.update_multi_fields(user_info["uid"], updated_fields)

    @gen.coroutine
    def change_user_info(self, user, university, college, gender, real_name, nick_name):
        self.add_to_statistic(university, college, user)
        updated_fields = {"university": university, "college": college,
                          "university_id": self._udb.get_university_id(university),
                          "university_short_name": self._udb.get_short_name(university),
                          "nick_name": nick_name, "real_name": real_name, 'gender': gender}
        user_info = yield self._db.users.find_and_modify({"user": user},
                                    {"$set": updated_fields})
        if user_info:
            # patch for user
            yield self._db.coins_of_user.update({"uid": user_info["uid"]}, {"$set": {"user": user_info["user"]}}, upsert=False)
        db_user = self.get_cached_user(user)
        yield self._user_searcher.update_multi_fields(user_info["uid"], updated_fields)
        if db_user:
            db_user["university"] = university
            db_user["college"] = college
            db_user["university_id"] = self._udb.get_university_id(university)
            db_user["nick_name"] = nick_name
            db_user["real_name"] = real_name
            db_user["gender"] = gender
            self.set_cached_user(user, db_user)

    @gen.coroutine
    def change_user_basic_info(self, user, info_dict):
        #yield self._db.users.update({"user": user}, {"$set": info_dict})
        user_info = yield self._db.users.find_and_modify({"user": user},
                                    {"$set": info_dict})
        if user_info:
            yield self._user_searcher.update_multi_fields(user_info["uid"], info_dict)
        preview_cached_key = self._REDIS_USER_INFO+"preview:"+user
        cached_key = self._REDIS_USER_INFO+user
        self._redis_cache.delete(preview_cached_key)
        self._redis_cache.delete(cached_key)

    @gen.coroutine
    def get_user_info(self, user):
        auth_fields = {"university": 1, "college": 1, "tags": 1,
                       "nick_name": 1, "entrance_year": 1, "degree": 1,
                       "real_name": 1, 'gender': 1, "_id": 0}
        for _, v in STAR_CLASS.iteritems():
            auth_fields[v] = 1
        ret = yield self._db.users.find_one({"user": user}, auth_fields)
        raise gen.Return(ret)

    @gen.coroutine
    def insert_my_tags(self, user, uid, tags_with_class):
        yield [self._db.users.update({"user": user}, {"$inc": {"tags."+tag: 1}, "$addToSet": {"tags_list": tag}}, upsert=True) for tag in tags_with_class]
        self._user_searcher.add_to_set(uid, "tags_list", tags_with_class)

    @gen.coroutine
    def insert_my_interested_tags(self, user, tag_with_class):
        assert ":" in tag_with_class
        tag_with_class = utf8(tag_with_class)
        user_info = yield self._db.users.find_and_modify({"user": user}, {"$addToSet": {"interested_tags": tag_with_class}}, upsert=True)
        pipe = self._redis_cache.pipeline()
        key = self._REDIS_EXPERIENCE_TAG+user
        pipe.sadd(key, tag_with_class)
        pipe.expire(key, self.TWO_DAY)
        pipe.execute()
        if user_info and "university_id" in user_info:
            university_id = user_info["university_id"]
            # self._hot_board.user_tag_change(user, university_id)

    @gen.coroutine
    def remove_my_interested_tags(self, user, tag_with_class):
        assert ":" in tag_with_class
        tag_with_class = utf8(tag_with_class)
        user_info = yield self._db.users.find_and_modify({"user": user}, {"$pull": {"interested_tags": tag_with_class}})
        pipe = self._redis_cache.pipeline()
        key = self._REDIS_EXPERIENCE_TAG+user
        pipe.srem(key, tag_with_class)
        pipe.expire(key, self.TWO_DAY)
        pipe.execute()
        if user_info and "university_id" in user_info:
            university_id = user_info["university_id"]
            # self._hot_board.user_tag_change(user, university_id)

    @gen.coroutine
    def get_my_interested_tags(self, user, force_db=False):
        key = self._REDIS_EXPERIENCE_TAG+user
        ret = self._redis_cache.smembers(key)
        if force_db or ret is None:
            data = yield self._db.users.find_one({"user": user}, {"interested_tags": 1})
            if data and "interested_tags" in data:
                tags = [utf8(tag) for tag in data["interested_tags"]]
                pipe = self._redis_cache.pipeline()
                key = self._REDIS_EXPERIENCE_TAG+user
                for tag in tags:
                    pipe.sadd(key, tag)
                pipe.expire(key, self.TWO_DAY)
                pipe.execute()
                raise gen.Return(set(tags))
            else:
                raise gen.Return(set())
        else:
            raise gen.Return(ret)

    @gen.coroutine
    def get_thumb_num(self, user):
        user = yield self._db.users.find_one({"user": user}, {"thumb_num": 1})
        if user and "thumb_num" in user:
            raise gen.Return(user["thumb_num"])
        else:
            raise gen.Return(0)

    @gen.coroutine
    def get_post_num_by_tag(self, user, tag_class):
        user_info = yield self.get_user_info(user)
        ret = 0
        tag_class = to_unicode(tag_class)
        if user_info and "tags" in user_info:
            for tag in user_info["tags"]:
                if tag_class in tag:
                    ret += 1
        raise gen.Return(ret)


    # TODO add to experience manager
    @gen.coroutine
    def inc_thumb_num(self, user):
        user_info = yield self._db.users.find_and_modify({"user": user}, {"$inc": {"thumb_num": 1}}, upsert=True)
        if user_info:
            user_info["thumb_num"] = 1 if "thumb_num" not in user_info else user_info["thumb_num"]+1
            if "uid" in user_info:
                yield self._user_searcher.update_multi_fields(user_info["uid"], {"thumb_num": user_info["thumb_num"]})

    @gen.coroutine
    def inc_thanks_coin(self, user, how_much):
        yield self._db.users.update({"user": user}, {"$inc": {"thanks_coin": how_much}}, upsert=True)

    @gen.coroutine
    def inc_answers_num(self, user):
        yield self._db.users.update({"user": user}, {"$inc": {"answers_num": 1}}, upsert=True)

    @gen.coroutine
    def follow(self, user, follower):
        if user == follower:
            return
        # TODO FIXME may this doc will exceed max 18MB.
        user1, user2 = yield [self._db.followers.find_and_modify({"user": user}, {"$addToSet": {"followers": follower}}, upsert=True),
               self._db.followers.find_and_modify({"user": follower}, {"$addToSet": {"following": user}}, upsert=True)]
        if not user1 or "followers" not in user1 or follower not in user1["followers"]:
            yield [self._db.users.update({"user": user}, {"$inc": {"followers_num": 1}}, upsert=True),
                   self._db.users.update({"user": follower}, {"$inc": {"following_num":1}}, upsert=True)]
            # pipe = self._redis_cache.pipeline()
            # key = self._REDIS_USER_FOLLOWERS+user
            # pipe.sadd(key, follower)
            # pipe.expire(key, self.TWO_DAY)
            # pipe.execute()
            raise gen.Return(True)
        else:
            raise gen.Return(False)

    @gen.coroutine
    def unfollow(self, user, follower):
        if user == follower:
            return
        # TODO FIXME may this doc will exceed max 18MB.
        user1, user2 = yield [self._db.followers.find_and_modify({"user": user}, {"$pull": {"followers": follower}}, upsert=True),
               self._db.followers.find_and_modify({"user": follower}, {"$pull": {"following": user}}, upsert=True)]
        if user1 and follower in user1["followers"]:
            yield [self._db.users.update({"user": user}, {"$inc": {"followers_num": -1}}),
                   self._db.users.update({"user": follower}, {"$inc": {"following_num": -1}})]
            # pipe = self._redis_cache.pipeline()
            # key = self._REDIS_USER_FOLLOWERS+user
            # pipe.srem(key, follower)
            # pipe.expire(key, self.TWO_DAY)
            # pipe.execute()
            raise gen.Return(True)
        else:
            raise gen.Return(False)

    @gen.coroutine
    def get_following_users(self, user):
        doc = yield self._db.followers.find_one({"user": user}, {"_id":0, "following":1})
        if doc and "following" in doc:
            ret = yield [self.find_user(_, True) for _ in doc["following"] if _]
        else:
            ret = []
        raise gen.Return(sorted(ret, key=lambda x: pinyin(to_unicode(("real_name" in x and x["real_name"]) or ""), style=TONE2)))

    @gen.coroutine
    def get_followers(self, user, use_cache=True):
        doc = yield self._db.followers.find_one({"user": user}, {"_id":0, "followers":1})
        if doc and "followers" in doc:
            ret = set(doc["followers"])
        else:
            ret = set()
        raise gen.Return(ret)

    @gen.coroutine
    def get_my_tags(self, user, use_cache=True):
        key = self._REDIS_USER_TAG_LIST+user
        tags = self._redis_cache.get(key)
        if use_cache and tags:
            ret = json.loads(tags)
        else:
            doc = yield self._db.users.find_one({"user": user}, {"_id":0, "tags":1})
            if doc and "tags" in doc:
                ret = doc["tags"]
                if ret:
                    self._redis_cache.setex(key, self.TWO_MINUTES, json.dumps(ret))
            else:
                ret = []
        raise gen.Return(ret)

    @gen.coroutine
    def get_user_by_tag(self, tag_with_class, university=None, use_cache=True):
        # TODO unit test and use cache
        if university:
            university = utf8(university)
            cache_key = "users:tagged:" + university + ":" + tag_with_class
        else:
            cache_key = "users:tagged:" + tag_with_class
        users_list_str = self._redis_cache.get(cache_key)
        if use_cache and users_list_str:
            users_list = json.loads(users_list_str)
        else:
            if university:
                cursor = self._db.users.find({"tags_list": tag_with_class, "university_id": self._udb.get_university_id(university)}, self.PREVIEW_FIELDS)
            else:
                cursor = self._db.users.find({"tags_list": tag_with_class}, self.PREVIEW_FIELDS)
            cursor = cursor.sort([("thumb_num", self._DESCENDING)]).limit(self.MAX_USER_CNT)
            users_list = yield cursor.to_list(None)
            self._redis_cache.setex(cache_key, 30 * 60, json.dumps(users_list))
        raise gen.Return(users_list)

    @gen.coroutine
    def get_user_by_thumb_num(self, university=None, page=1, use_cache=True):
        if university:
            cache_key = "users:recommended:" + university
        else:
            cache_key = "users:recommended"
        users_list_str = self._redis_cache.get(cache_key)
        if use_cache and users_list_str:
            users_list = json.loads(users_list_str)
        else:
            fields = dict(self.PREVIEW_FIELDS)
            del fields["password"]
            if university:
                cursor = self._db.users.find({"university_id": self._udb.get_university_id(university)}, fields)
            else:
                cursor = self._db.users.find({}, fields)
            cursor = cursor.sort([("thumb_num", self._DESCENDING)]).limit(self.MAX_USER_CNT)
            users_list = yield cursor.to_list(None)
            self._redis_cache.setex(cache_key, 60 * 60, json.dumps(users_list))
        raise gen.Return([(len(users_list) + self.PAGE_NUM - 1) / self.PAGE_NUM, page,
                      users_list[(page - 1) * self.PAGE_NUM:page * self.PAGE_NUM]])

    @gen.coroutine
    def search_user(self, keyword, current_page, use_cache=True):
        cache_key = "user:search:user:"******"set"):
        field = to_unicode(field)
        if field in STAR_CLASS:
            if operation == "set":
                yield self._db.users.update({"user": user}, {"$set": {STAR_CLASS[field]: 1}, "$addToSet": {"star_info": STAR_CLASS[field]}})
            else:
                yield self._db.users.update({"user": user}, {"$unset": {STAR_CLASS[field]: 1}, "$pull": {"star_info": STAR_CLASS[field]}})
            db_user = self.get_cached_user(user)
            if db_user:
                if operation == "set":
                    db_user[STAR_CLASS[field]] = 1
                else:
                    if STAR_CLASS[field] in db_user:
                        del db_user[STAR_CLASS[field]]
                self.set_cached_user(user, db_user)
            raise gen.Return(True)
        else:
            raise gen.Return(False)

    @gen.coroutine
    def set_star_user(self, user, field):
        ret = yield self.star_user_helper(user, field, "set")
        raise gen.Return(ret)

    @gen.coroutine
    def unset_star_user(self, user, field):
        ret = yield self.star_user_helper(user, field, "unset")
        raise gen.Return(ret)

    @gen.coroutine
    def get_top_star_users(self, use_cache=True):
        ret = {}
        for k,v in STAR_CLASS.iteritems():
            cache_key = "users:star:" + v
            users_list_str = self._redis_cache.get(cache_key)
            if use_cache and users_list_str:
                users_list = json.loads(users_list_str)
            else:
                cursor = self._db.users.find({"star_info": v}, self.PREVIEW_FIELDS)
                cursor = cursor.sort([("thumb_num", self._DESCENDING)]).limit(self.TOP_STAR_USER_CNT)
                users_list = yield cursor.to_list(None)
                if users_list:
                    self._redis_cache.setex(cache_key, 30 * 60, json.dumps(users_list))
            ret[k] = users_list
        raise gen.Return(ret)

    @gen.coroutine
    def get_some_recommended_users(self, page=1, use_cache=True):
        cache_key = "users:recommended:random"
        users_list_str = self._redis_cache.get(cache_key)
        if use_cache and users_list_str:
            users_list = json.loads(users_list_str)
        else:
            fields = dict(self.PREVIEW_FIELDS)
            del fields["password"]
            cursor = self._db.users.find({}, fields)
            cursor = cursor.sort([("thumb_num", self._DESCENDING)]).limit(200)
            users_list = yield cursor.to_list(None)
            if users_list:
                self._redis_cache.setex(cache_key, 30 * 60, json.dumps(users_list))
        raise gen.Return([(len(users_list)+self.PAGE_NUM-1)/self.PAGE_NUM, page,
                          users_list[((page-1)*self.PAGE_NUM):(page*self.PAGE_NUM)]])

    @gen.coroutine
    def get_rank(self):
        cache_key = "user:rank:by_total_study_coin"
        rank_list = self._redis_cache.get(cache_key)
        if not rank_list:
            res = yield self.get_total_rank_helper()
            rank_list = json.dumps({"data": res, "type": 6})
            self._redis_cache.setex(cache_key, 24 * 60, rank_list)
        raise gen.Return(rank_list)

    @gen.coroutine
    def get_total_rank_helper(self, sort_item="coins_by_study"):
        cursor2 = self._db.coins_of_user.find({}, {"uid": 1, sort_item: 1, "_id": 0, "user": 1}).sort([(sort_item, -1),]).limit(100)
        user_list = yield cursor2.to_list(None)
        ret = []
        for item in user_list:
            if "user" in item:
                user_info = yield self.find_user(item["user"], preview=True)
            else:
                user_info = yield self.find_user_by_id(item["uid"])
            if user_info:
                item_data = {}
                item_data["nick_name"] = user_info["nick_name"]
                item_data["icon"] = user_info["icon"]
                item_data["coin"] = int(item["coins_by_study"])
                item_data["uid"] = item["uid"]
                item_data["delta"] = item_data["coin"]
                item_data.update(user_info)
                ret.append(item_data)
        raise gen.Return(ret)

    def is_star_user(self, user_info):
        for _, v in STAR_CLASS.iteritems():
            if v in user_info:
                return True
        return False

    @gen.coroutine
    def get_today_users(self):
        fields = dict(self.PREVIEW_FIELDS)
        del fields["password"]
        cursor = self._db.users.find({"index_ctime": {"$gt": seconds_of_today_at_wee_hours()}}, fields)
        users_list = yield cursor.to_list(None)
        raise gen.Return(users_list)
예제 #14
0
class TestUserSearch(AsyncTestCase):
    def setUp(self):
        super(TestUserSearch, self).setUp()
        self.es_connection = ESConnection("localhost", 9200, self.io_loop)
        self.us = ESSearch(index_mapping=user_index_mapping,
                           index_name="index",
                           type_name="user",
                           analyze_fields=user_analyze_fields,
                           none_analyze_fields=user_none_analyze_fields,
                           io_loop=self.io_loop)
        self.io_loop.run_sync(self.setup_coro)

    @gen.coroutine
    def setup_coro(self):
        yield self.us.clean_all()

    @gen_test
    def test_insert(self):
        uid, info_dict = test_case[0]
        response = yield self.us.insert(uid, info_dict)
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        self.assertIn('refresh=True', response.request.url)

    @gen_test
    def test_get(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        res = yield self.us.get(uid)
        self.assertEqual(info_dict, res['_source'])

    @gen_test
    def test_delete(self):
        uid, info_dict = test_case[0]
        res = yield self.us.delete(uid)
        self.assertEqual(res.code, 404)
        response = yield self.us.insert(uid, info_dict)
        res = yield self.us.delete(uid)
        self.assertEqual(res.code, 200)

    @gen_test
    def test_update_field(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        response = yield self.us.update_field(uid, 'real_name', '小美')
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(response['real_name'], u"小美")

    @gen_test
    def test_update_multi_fields(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        response = yield self.us.update_multi_fields(uid, {
            'real_name': '小美',
            'tags_list': ['a', 'b']
        })
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(response['real_name'], u"小美")
        self.assertEqual(response['tags_list'], ['a', 'b'])

    @gen_test
    def test_push(self):
        uid, info_dict = test_case[0]
        tags_list = info_dict['tags_list']
        yield self.us.insert(uid, info_dict)
        yield self.us.push(uid, "tags_list", 'a')
        tags_list.append('a')
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(response['tags_list'], tags_list)

        yield self.us.push(uid, "tags_list", ['a', 'b'])
        tags_list.extend(['a', 'b'])
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(response['tags_list'], tags_list)

    @gen_test
    def test_add_to_set(self):
        uid, info_dict = test_case[0]
        tags_list = info_dict['tags_list']
        yield self.us.insert(uid, info_dict)
        yield self.us.add_to_set(uid, "tags_list", 'a')
        tags_list.append('a')
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(sorted(response['tags_list']), sorted(tags_list))

        yield self.us.add_to_set(uid, "tags_list", ['a', 'b'])
        tags_list = set(tags_list).union(['a', 'b'])
        tags_list = list(tags_list)
        response = yield self.es_connection.get(index="index",
                                                type="user",
                                                uid=uid)
        response = response["_source"]
        self.assertEqual(sorted(response['tags_list']), sorted(tags_list))

    @gen_test
    def test_query(self):
        for uid, info_dict in test_case[:2]:
            yield self.us.insert(uid, info_dict)
        response = yield self.us.query(u"校园")
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 2)

        response = yield self.us.query(u"软件大赛")
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 1)
        self.assertEqual(response["hits"]["hits"][0]["_id"], '1')

        response = yield self.us.query(u'电子科技大学')
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 2)
        self.assertEqual(response["hits"]["hits"][0]["_id"], '2')

    def _verify_status_code_and_return_response(self, response):
        self.assertTrue(response.code in [200, 201],
                        "Wrong response code: %d." % response.code)
        response = escape.json_decode(response.body)
        return response
예제 #15
0
class TestUserSearch(AsyncTestCase):
    def setUp(self):
        super(TestUserSearch, self).setUp()
        self.es_connection = ESConnection("localhost", 9200, self.io_loop)
        self.us = ESSearch(index_mapping=user_index_mapping,
                           index_name="index",
                           type_name="user",
                           analyze_fields=user_analyze_fields,
                           none_analyze_fields=user_none_analyze_fields,
                           io_loop=self.io_loop)
        self.io_loop.run_sync(self.setup_coro)

    @gen.coroutine
    def setup_coro(self):
        yield self.us.clean_all()

    @gen_test
    def test_insert(self):
        uid, info_dict = test_case[0]
        response = yield self.us.insert(uid, info_dict)
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        self.assertIn('refresh=True', response.request.url)

    @gen_test
    def test_get(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        res = yield self.us.get(uid)
        self.assertEqual(info_dict, res['_source'])

    @gen_test
    def test_delete(self):
        uid, info_dict = test_case[0]
        res = yield self.us.delete(uid)
        self.assertEqual(res.code, 404)
        response = yield self.us.insert(uid, info_dict)
        res = yield self.us.delete(uid)
        self.assertEqual(res.code, 200)

    @gen_test
    def test_update_field(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        response = yield self.us.update_field(uid, 'real_name', '小美')
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(response['real_name'], u"小美")

    @gen_test
    def test_update_multi_fields(self):
        uid, info_dict = test_case[0]
        yield self.us.insert(uid, info_dict)
        response = yield self.us.update_multi_fields(uid, {'real_name': '小美', 'tags_list': ['a', 'b']})
        response_dict = self._verify_status_code_and_return_response(response)
        self.assertEqual(response_dict['_index'], 'index')
        self.assertEqual(response_dict['_type'], 'user')
        self.assertEqual(response_dict['_id'], uid)
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(response['real_name'], u"小美")
        self.assertEqual(response['tags_list'], ['a', 'b'])

    @gen_test
    def test_push(self):
        uid, info_dict = test_case[0]
        tags_list = info_dict['tags_list']
        yield self.us.insert(uid, info_dict)
        yield self.us.push(uid, "tags_list", 'a')
        tags_list.append('a')
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(response['tags_list'], tags_list)

        yield self.us.push(uid, "tags_list", ['a', 'b'])
        tags_list.extend(['a', 'b'])
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(response['tags_list'], tags_list)

    @gen_test
    def test_add_to_set(self):
        uid, info_dict = test_case[0]
        tags_list = info_dict['tags_list']
        yield self.us.insert(uid, info_dict)
        yield self.us.add_to_set(uid, "tags_list", 'a')
        tags_list.append('a')
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(sorted(response['tags_list']), sorted(tags_list))

        yield self.us.add_to_set(uid, "tags_list", ['a', 'b'])
        tags_list = set(tags_list).union(['a', 'b'])
        tags_list = list(tags_list)
        response = yield self.es_connection.get(index="index", type="user", uid=uid)
        response = response["_source"]
        self.assertEqual(sorted(response['tags_list']), sorted(tags_list))

    @gen_test
    def test_query(self):
        for uid, info_dict in test_case[:2]:
            yield self.us.insert(uid, info_dict)
        response = yield self.us.query(u"校园")
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 2)

        response = yield self.us.query(u"软件大赛")
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 1)
        self.assertEqual(response["hits"]["hits"][0]["_id"], '1')

        response = yield self.us.query(u'电子科技大学')
        response = self._verify_status_code_and_return_response(response)
        self.assertEqual(response["hits"]["total"], 2)
        self.assertEqual(response["hits"]["hits"][0]["_id"], '2')

    def _verify_status_code_and_return_response(self, response):
        self.assertTrue(response.code in [200, 201], "Wrong response code: %d." % response.code)
        response = escape.json_decode(response.body)
        return response