async def api_user_authenticate(request): """ 用户登录验证API函数 :param request: 请求对象 :return: 回响消息, 并且设置COOKIE """ request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') email = request_data.email password = request_data.password if not email: return data_error(u'非法邮箱账号') if not password: return data_error(u'非法密码') users = await UserAuth.find_all(where='email=?', args=[email]) if len(users) == 0: return data_error(u'账号不存在') user = users[0] sha1_password = generate_sha1_password(user['id'], password) if user['password'] != sha1_password: return data_error(u'密码有误') cookie_name = configs.user_cookie.name cookie_secret = configs.user_cookie.secret cookie_str = user_cookie_generate(user['id'], 86400, cookie_secret) r = web.Response() r.set_cookie(cookie_name, cookie_str, max_age=86400, httponly=True) user['password'] = '******' r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r
async def api_image_upload(request): """ 上传图片API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() ct = request.content_type.lower() if ct.startswith('application/json'): params = await request.json() if not isinstance(params, dict): return data_error() else: return data_error() image_name = None if 'name' in params: image_name = params['name'] image_str = None if 'image' in params: image_str = params['image'] if not image_name or not image_name.strip(): return data_error(u'图片名不能为空') if not image_str or not image_str.strip(): return data_error(u'图片内容不能为空') # 取消图片的原始名,只保留后缀名 loc = image_name.find('.') if loc == -1: return data_error(u'图片名有误') image_name = image_name[loc:] # 先在数据库中生成一条图片的记录 image = Image(url='xx') await image.save() # 使用图片数据的创建时间做为URL image_url = '/static/img/' image_url += str(int(image.created_at * 1000)) image_url += image_name image.url = (configs.domain_name + image_url) await image.update() image_str = image_str.replace('data:image/png;base64,', '') image_str = image_str.replace('data:image/jpeg;base64,', '') image_data = base64.b64decode(image_str) image_path = '.' image_path += image_url file = open(image_path, 'wb') file.write(image_data) file.close() return image
async def api_image_upload(request): """ 上传图片API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') image_name_ext = request_data.name image_str = request_data.image if not image_name_ext or not image_name_ext.strip(): return data_error(u'图片名不能为空') if not image_str or not image_str.strip(): return data_error(u'图片内容不能为空') # 取消图片的原始名,只保留后缀名 loc = image_name_ext.find('.') if loc == -1: return data_error(u'图片名有误') image_name_ext = image_name_ext[loc:] # 先在数据库中生成一条图片的记录 image = Image(url='xx') await image.save() # 使用图片数据的创建时间做为URL image_url = '/static/img/' # 使用年月创建文件夹 dt = datetime.fromtimestamp(image.created_at) new_path = './static/img/%s/%s' % (dt.year, dt.month) os.makedirs(new_path, exist_ok=True) image_url += '%s/%s/%s%s%s%s' % \ (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) image_url += image_name_ext image.url = (configs.domain_name + image_url) await image.update() image_str = image_str.replace('data:image/png;base64,', '') image_str = image_str.replace('data:image/jpeg;base64,', '') image_str = image_str.replace('data:image/gif;base64,', '') image_data = base64.b64decode(image_str) image_path = '.' image_path += image_url file = open(image_path, 'wb') file.write(image_data) file.close() return image
async def api_comment_create(request): """ 创建评论API函数 :param request: 请求 :return: 返回响应消息 """ # 只有登录用户才能发表评论 user = request.__user__ if user is None: return data_error(u'请先登录') # 限制每10秒只能发送一条评论 comments = await Comment.find_all('user_id=? and created_at > ?', [user.id, time.time() - 10.0]) if len(comments) > 0: return data_error(u'评论过于频繁(10秒后再试)') # 获取评论内容 request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') # 检查评论内容 content = request_data.content if not content or not content.strip(): return data_error(u'评论内容不能为空') blog_id = request.match_info['blog_id'] blog = await Blog.find(blog_id) if blog is None: return data_error(u'评论的博客不存在') # 检查评论目标人名称,如果为NULL,表示对博客直接评论 target_user_name = request_data.target_name if not target_user_name or not target_user_name.strip(): target_user_name = blog.user_name # 检查评论目标人id,如果为NULL,表示对博客直接评论 target_user_id = request_data.target_id if not target_user_id or not target_user_id.strip(): target_user_id = blog.user_id comment = Comment(blog_id=blog.id, user_id=user.id, user_name=user.name, user_image=user.image, target_user_id=target_user_id, target_user_name=target_user_name, content=content.strip()) await comment.save() return comment
async def api_image_delete(request): """ 删除博客API函数 :param request: 请求 :return: """ if not is_admin(request): return permission_error() image_id = request.match_info['image_id'] image = await Image.find(image_id) if not image: return data_error(u'非法image id') url = image.url await image.remove() url = url.replace(configs.domain_name, '') filename = '.' filename += url if os.path.exists(filename): os.remove(filename) return dict(id=image_id)
async def blog_detail(request): """ 博客详细页面路由函数 :param request: 请求对象 :return: 博客详细页面 """ blog_id = request.match_info['blog_id'] # 根据博客ID找到博客详细内容 blog = await Blog.find(blog_id) if not blog: return data_error(u'非法blog id') # 阅读次数增加 blog.read_times += 1 await blog.update() # 找到指定博客ID的博客的评论 comments = await Comment.find_all('blog_id=?', [blog_id], order_by='created_at asc') for c in comments: c.html_content = text2html(c.content) blog.html_content = markdown2.markdown(blog.content) return { '__template__': 'blog_detail.html', 'blog': blog, 'comments': comments }
async def api_blog_update(request): """ 更新博客API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() ct = request.content_type.lower() if ct.startswith('application/json'): params = await request.json() if not isinstance(params, dict): return data_error() else: return data_error() blog_id = request.match_info['blog_id'] name = None if 'name' in params: name = params['name'] summary = None if 'summary' in params: summary = params['summary'] content = None if 'content' in params: content = params['content'] cover_image = None if 'cover_image' in params: cover_image = params['cover_image'] blog_type = None if 'type' in params: blog_type = params['type'] if not name or not name.strip(): return data_error(u'博客名称不能为空') if not summary or not summary.strip(): return data_error(u'博客摘要不能为空') if not content or not content.strip(): return data_error(u'博客内容不能为空') if not cover_image or not cover_image.strip(): return data_error(u'封面图片不能为空') if not blog_type or not blog_type.strip(): return data_error(u'博客类型不能为空') blog = await Blog.find(blog_id) if not blog: return data_error(u'非法blog id') blog.name = name.strip() blog.summary = summary.strip() blog.content = content.strip() blog.cover_image = cover_image.strip() blog.type = blog_type.strip() await blog.update() return blog
async def api_blog_create(request): """ 创建博客API函数 :param request: 请求 :return: """ if not is_admin(request): return permission_error() ct = request.content_type.lower() if ct.startswith('application/json'): params = await request.json() if not isinstance(params, dict): return data_error() else: return data_error() name = None if 'name' in params: name = params['name'] summary = None if 'summary' in params: summary = params['summary'] content = None if 'content' in params: content = params['content'] cover_image = None if 'cover_image' in params: cover_image = params['cover_image'] blog_type = None if 'type' in params: blog_type = params['type'] if not name or not name.strip(): return data_error(u'博客名称不能为空') if not summary or not summary.strip(): return data_error(u'博客摘要不能为空') if not content or not content.strip(): return data_error(u'博客内容不能为空') if not cover_image or not cover_image.strip(): return data_error(u'封面图片不能为空') if not blog_type or not blog_type.strip(): return data_error(u'博客类型不能为空') blog = Blog(user_id=request.__user__['id'], user_name=request.__user__['name'], user_image=request.__user__['image'], name=name.strip(), summary=summary.strip(), content=content.strip(), cover_image=cover_image.strip(), read_times=0, type=blog_type) await blog.save() return blog
async def api_blog_type_create(request): """ 创建博客类别API函数 :param request: 请求对象 :return: 博客类别数据 """ if not is_admin(request): return permission_error() request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') name = request_data.name level = request_data.level if not name or not name.strip(): return data_error(u'类别名称不能为空') if not level or not level.strip(): return data_error(u'类别优先级不能为空') blog_type = BlogType(name=name.strip(), level=int(level.strip())) await blog_type.save() return blog_type
async def api_blog_get_one(request): """ 获取指定ID的博客数据函数 :param request: 请求对象 :return: 博客数据 """ if not is_admin(request): return permission_error() blog_id = request.match_info['blog_id'] blog = await Blog.find(blog_id) if not blog: return data_error(u'非法blog id') return blog
async def api_comment_delete(request): """ 删除评论API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() comment_id = request.match_info['id'] c = await Comment.find(comment_id) if c is None: return data_error(u'非法comment id') await c.remove() return dict(id=comment_id)
async def api_blog_type_delete(request): """ 删除博客类别API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() type_id = request.match_info['type_id'] # 根据博客类别ID找到类别 blog_type = await BlogType.find(type_id) if not blog_type: return data_error(u'非法type id') await blog_type.remove() return dict(id=type_id)
async def api_blog_delete(request): """ 删除博客API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() blog_id = request.match_info['blog_id'] # 根据博客ID找到博客详细内容 blog = await Blog.find(blog_id) if not blog: return data_error(u'非法blog id') await blog.remove() return dict(id=blog_id)
async def api_blog_update(request): """ 更新博客API函数 :param request: 请求对象 :return: """ if not is_admin(request): return permission_error() request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') blog_id = request.match_info['blog_id'] name = request_data.name summary = request_data.summary content = request_data.content cover_image = request_data.cover_image blog_type = request_data.type if not name or not name.strip(): return data_error(u'博客名称不能为空') if not summary or not summary.strip(): return data_error(u'博客摘要不能为空') if not content or not content.strip(): return data_error(u'博客内容不能为空') if not cover_image or not cover_image.strip(): return data_error(u'封面图片不能为空') if not blog_type or not blog_type.strip(): return data_error(u'博客类型不能为空') blog = await Blog.find(blog_id) if not blog: return data_error(u'非法blog id') blog.name = name.strip() blog.summary = summary.strip() blog.content = content.strip() blog.cover_image = cover_image.strip() blog.type = blog_type.strip() await blog.update() return blog
async def api_comment_create(request): """ 创建评论API函数 :param request: 请求 :return: 返回响应消息 """ # 只有登录用户才能发表评论 user = request.__user__ if user is None: return data_error(u'请先登录') # 限制每10秒只能发送一条评论 comments = await Comment.find_all('user_id=? and created_at > ?', [user.id, time.time() - 10.0]) if len(comments) > 0: return data_error(u'评论过于频繁(10秒后再试)') # 获取评论内容 ct = request.content_type.lower() if ct.startswith('application/json'): params = await request.json() if not isinstance(params, dict): return data_error() else: return data_error() # 检查评论内容 content = None if 'content' in params: content = params['content'] if not content or not content.strip(): return data_error(u'评论内容不能为空') blog_id = request.match_info['blog_id'] blog = await Blog.find(blog_id) if blog is None: return data_error(u'评论的博客不存在') comment = Comment(blog_id=blog.id, user_id=user.id, user_name=user.name, user_image=user.image, content=content.strip()) await comment.save() return comment
async def api_user_authenticate(request): """ 用户登录验证API函数 :param request: 请求对象 :return: 回响消息, 并且设置COOKIE """ ct = request.content_type.lower() if ct.startswith('application/json'): params = await request.json() if not isinstance(params, dict): return data_error() else: return data_error() email = None if 'email' in params: email = params['email'] password = None if 'password' in params: password = params['password'] if not email: return data_error(u'非法邮箱账号') if not password: return data_error(u'非法密码') users = await UserAuth.find_all(where='email=?', args=[email]) if len(users) == 0: return data_error(u'账号不存在') user = users[0] sha1_password = generate_sha1_password(user['id'], password) if user['password'] != sha1_password: return data_error(u'密码有误') cookie_name = configs.user_cookie.name cookie_secret = configs.user_cookie.secret cookie_str = user_cookie_generate(user['id'], 86400, cookie_secret) r = web.Response() r.set_cookie(cookie_name, cookie_str, max_age=86400, httponly=True) user['password'] = '******' r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r
async def api_blog_create(request): """ 创建博客API函数 :param request: 请求 :return: """ if not is_admin(request): return permission_error() request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') name = request_data.name summary = request_data.summary content = request_data.content cover_image = request_data.cover_image blog_type = request_data.type if not name or not name.strip(): return data_error(u'博客名称不能为空') if not summary or not summary.strip(): return data_error(u'博客摘要不能为空') if not content or not content.strip(): return data_error(u'博客内容不能为空') if not cover_image or not cover_image.strip(): return data_error(u'封面图片不能为空') if not blog_type or not blog_type.strip(): return data_error(u'博客类型不能为空') blog = Blog(user_id=request.__user__['id'], user_name=request.__user__['name'], user_image=request.__user__['image'], name=name.strip(), summary=summary.strip(), content=content.strip(), cover_image=cover_image.strip(), read_times=0, type=blog_type) await blog.save() return blog
async def api_github_login(request): """ GitHub登录API函数 :param request: :return: """ qs_parser = QueryStringParser(request.query_string) github_code = qs_parser.code last_url = qs_parser.state if not github_code: return data_error('GitHub Code Lost') # 获取用户令牌 access_token_url = 'https://github.com/login/oauth/access_token?client_id=' access_token_url += configs.github.client_id access_token_url += '&client_secret=' access_token_url += configs.github.client_secret access_token_url += '&redirect_uri=' access_token_url += configs.github.redirect_uri access_token_url += '&code=' access_token_url += github_code async with ClientSession() as session: async with session.post(access_token_url) as response: response_data = await response.text() data_parser = QueryStringParser(response_data) access_token = data_parser.access_token if not access_token: return data_error() user_url = 'https://api.github.com/user?access_token=' user_url += access_token async with ClientSession() as session: async with session.get(user_url) as response: user_data = await response.json() user_id = None if 'id' in user_data: user_id = user_data['id'] if not user_id: return data_error() user_name = None if 'login' in user_data: user_name = user_data['login'] if not user_name: return data_error() user_image = None if 'avatar_url' in user_data: user_image = user_data['avatar_url'] if not user_image: return data_error() # 更新或者保存用户信息 user = await UserInfo.find(str(user_id)) logging.info(user) if not user: user = UserInfo(id=user_id, name=user_name, image=user_image) await user.save() else: user.name = user_name user.image = user_image await user.update() # 生成用户COOKIE cookie_name = configs.user_cookie.name cookie_secret = configs.user_cookie.secret cookie_str = user_cookie_generate(str(user_id), 86400, cookie_secret) r = web.HTTPFound(last_url) r.set_cookie(cookie_name, cookie_str, max_age=86400, httponly=True) return r
async def api_user_register(request): """ 用户注册API函数 :param request: 请求对象 :return: 注册成功则设置COOKIE,返回响应消息 """ _RE_EMAIL = re.compile( r'^[a-z0-9\.\-\_]+\@[a-z0-9\-\_]+(\.[a-z0-9\-\_]+){1,4}$') _RE_SHA1 = re.compile(r'^[0-9a-f]{40}$') request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') name = request_data.name email = request_data.email password = request_data.password verify = request_data.verify # 检查验证码是否输入正确 if not verify or not verify.strip(): return data_error(u'非法验证码') verify_cookie_name = configs.verify_image_cookie.name cookie_secret = configs.verify_image_cookie.secret cookie_str = request.cookies.get(verify_cookie_name) cookie_str_input = verify_image_cookie_generate(verify.upper(), cookie_secret) if not cookie_str == cookie_str_input: return data_error(u'验证码错误') # 检查用户数据是否合法 if not name or not name.strip(): return data_error(u'非法用户名') if not email or not _RE_EMAIL.match(email): return data_error(u'非法邮箱账号') if not password or not _RE_SHA1.match(password): return data_error(u'非法密码') # 检查用户邮箱是否已经被注册 users = await UserAuth.find_all(where='email=?', args=[email]) if len(users) > 0: return data_error(u'邮箱已经被使用') # 生成用户ID, 并且混合用户ID和密码进行SHA1加密 uid = generate_id() sha1_password = generate_sha1_password(uid, password) # 将新用户数据保存到数据库中 user = UserAuth(id=uid, email=email, password=sha1_password) await user.save() # 生成头像图片URL head_img_url = configs.domain_name head_img_url += '/static/img/head_%s.jpg' % random.randint(1, 15) user_info = UserInfo(id=uid, name=name.strip(), image=head_img_url) await user_info.save() # 生成COOKIE cookie_str = user_cookie_generate(user['id'], 86400, configs.user_cookie.secret) cookie_name = configs.user_cookie.name # 生成响应消息 r = web.Response() # 删除用于验证验证码的COOKIE r.set_cookie(verify_cookie_name, '-deleted-', max_age=0, httponly=True) r.set_cookie(cookie_name, cookie_str, max_age=86400, httponly=True) user['password'] = '******' r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r
async def api_weibo_login(request): """ 微博登录API函数 :param request: :return: """ request_data = RequestData(request) if not await request_data.json_load(): return data_error(u'非法数据格式, 请使用JSON格式') # 取出用户id和访问令牌 uid = request_data.uid if not uid: return data_error() access_token = request_data.access_token if not access_token or not access_token.strip(): return data_error() # 获取用户数据 url = 'https://api.weibo.com/2/users/show.json?access_token=' url += access_token url += '&uid=' url += str(uid) async with ClientSession() as session: async with session.get(url) as response: user_data = await response.json() logging.info(user_data) if not isinstance(user_data, dict): return data_error() user_name = None if 'screen_name' in user_data: user_name = user_data['screen_name'] if not user_name: return data_error() user_image = None if 'avatar_hd' in user_data: user_image = user_data['avatar_hd'] if not user_image: return data_error() # 更新或者保存用户信息 user = await UserInfo.find(str(uid)) logging.info(user) if not user: user = UserInfo(id=uid, name=user_name, image=user_image) await user.save() else: user.name = user_name user.image = user_image await user.update() # 生成用户COOKIE cookie_name = configs.user_cookie.name cookie_secret = configs.user_cookie.secret cookie_str = user_cookie_generate(str(uid), 86400, cookie_secret) r = web.Response() r.set_cookie(cookie_name, cookie_str, max_age=86400, httponly=True) r.content_type = 'application/json' r.body = json.dumps(user, ensure_ascii=False).encode('utf-8') return r