def _get_board_posts(board_type): table_name = db.table.board(board_type) page = request.args.get('page', 1) # if unknown board type if not table_name: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) from modules.pagination import Pagination fetch_query_str = """ SELECT `b`.*, '!user', `u`.* FROM `{}` `b` INNER JOIN `users` `u` ON (`u`.`user_id` = `b`.`user_id`) """.format(table_name) count_query_str = "SELECT COUNT(*) AS `cnt` FROM `{}`".format(table_name) order_query_str = "ORDER BY `post_id` DESC" with db.engine_rdonly.connect() as connection: return helper.response_ok( Pagination(connection=connection, fetch=fetch_query_str, count=count_query_str, order=order_query_str, current_page=page).get_result(db.to_relation_model))
def _delete_draftbox(board_type): user_id = request.user['user_id'] with db.engine_rdwr.connect() as connection: db.statement(db.table.DRAFT_BOX).where(user_id=user_id, board_type=board_type).limit(1).delete(connection) return helper.response_ok({'status': 'success'})
def _modify_board_comment(board_type, comment_id): json_form = request.get_json(force=True, silent=True) content = json_form.get('content') user_id = request.user['user_id'] if not isinstance(content, str): return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) table_name = db.table.comment(board_type) # if unknown board type if not table_name: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) statement = db.Statement(table_name).set(content=content)\ .where(user_id=user_id, comment_id=comment_id, status='posted') with db.engine_rdwr.connect() as connection: updated = statement.update(connection).rowcount if updated: return helper.response_ok({'status': 'success'}) else: return helper.response_err(ER.AUTHENTICATION_FAILED, ER.AUTHENTICATION_FAILED_MSG)
def _delete_post(board_type, post_id): """ Delete a post that user has. """ user_id = request.user['user_id'] table_name = db.table.board(board_type) # if unknown board type if not table_name: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) statement = db.Statement(table_name)\ .set(status='deleted')\ .where(post_id=post_id, user_id=user_id, status='posted') with db.engine_rdwr.connect() as connection: deleted = statement.update(connection).rowcount # if the post does not exist or is not the user's post if not deleted: return helper.response_err(ER.AUTHENTICATION_FAILED, ER.AUTHENTICATION_FAILED_MSG) return helper.response_ok({'status': 'success'})
def _login(): from modules.login import generate_jwt_token json_form = request.get_json(force=True, silent=True) address = json_form.get('address') signature = json_form.get('signature') signature_version = json_form.get('signature_version', 1) user_name = json_form.get('user_name', '') platform_type = json_form.get('platform_type') if platform_type not in PLATFORM_TYPES: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) web3 = get_web3() with db.engine_rdwr.connect() as connection: jwt_token = generate_jwt_token( connection, web3, address, signature, platform_type=platform_type, signature_version=signature_version, default_user_name=user_name ) if jwt_token: return helper.response_ok(jwt_token) else: return helper.response_err(ER.AUTHENTICATION_FAILED, ER.AUTHENTICATION_FAILED_MSG)
def _get_board_comment(board_type, comment_id): table_name = db.table.comment(board_type) # if unknown board type if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) statement = db.Statement(table_name).where(comment_id=comment_id, status='posted') subcomments_query_str = """ SELECT `c`.*, '!user', `u`.* FROM `{}` `c` INNER JOIN `users` `u` ON (`u`.`user_id` = `c`.`user_id`) WHERE `parent_comment_id` = :parent_comment_id AND `status` = :comment_status ORDER BY `c`.`created_at` ASC """.format(table_name) with db.engine_rdonly.connect() as connection: comment = statement.select(connection).fetchone() # if the comment does not exist if not comment: return helper.response_err(ERR.COMMON.NOT_EXIST) comment = db.to_relation_model(comment) subcomments = connection.execute( text(subcomments_query_str), parent_comment_id=comment['comment_id'], comment_status='posted') comment.update({'subcomments': db.to_relation_model_list(subcomments)}) return helper.response_ok(comment)
def _post_board_comment(board_type, post_id): json_form = request.get_json(force=True, silent=True) content = json_form.get('content') user_id = request.user['user_id'] if not isinstance(content, str): return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) table_name = db.table.comment(board_type) # if unknown board type if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) statement = db.Statement(table_name).set(user_id=user_id, post_id=post_id, content=content) with db.engine_rdwr.connect() as connection: try: comment_id = statement.insert(connection).lastrowid except IntegrityError: # if failed to insert return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) return helper.response_ok({'comment_id': comment_id})
def _put_draftbox(board_type): draft_box = json.dumps(request.get_json(force=True, silent=True)) user_id = request.user['user_id'] # if json is null, don't clear original data for safety. # the data can be cleared by DELETE method. if not draft_box: return helper.response_err(ERR.COMMON.NOT_ALLOWED_CONTENT_TYPE) put_query_stmt = """ INSERT INTO `user_post_drafts` SET `user_id` = :user_id, `board_type` = :board_type, `draft_box` = :draft_box ON DUPLICATE KEY UPDATE `board_type` = :board_type, `draft_box` = :draft_box """ with db.engine_rdwr.connect() as connection: connection.execute(text(put_query_stmt), user_id=user_id, board_type=board_type, draft_box=draft_box) return helper.response_ok({ 'status': 'success' })
def _get_draftbox(board_type): user_id = request.user['user_id'] with db.engine_rdonly.connect() as connection: draft_box_stmt = db.statement(db.table.DRAFT_BOX)\ .where(user_id=user_id, board_type=board_type).limit(1)\ .select(connection).fetchone() if draft_box_stmt is None: # if user's draftbox does not exist, return empty draft box return helper.response_ok({ board_type: [] }) else: return helper.response_ok(json.loads(draft_box_stmt['draft_box']))
def _put_user_info(): """ Modify user's info. Never change user_id, address. """ json_form = request.get_json(force=True, silent=True) user_id = request.user['user_id'] profile_file_id = json_form.get('profile_file_id') # only these columns can be changed changable_columns = ['name', 'youtube_url', 'facebook_url', 'soundcloud_url', 'spotify_url'] change_value = {} if isinstance(profile_file_id, int): change_value.update({'profile_file_id': profile_file_id}) for column in changable_columns: if column in json_form: change_value.update({column: json_form.get(column)}) if column == 'name' and len(change_value['name']) < 1: return helper.response_err(ERR.COMMON.TOO_SHORT_PARAMETER) with db.engine_rdwr.connect() as connection: try: db.statement(db.table.USERS).set(**change_value).where(user_id=user_id).update(connection) except IntegrityError: return helper.response_err(ERR.COMMON.ALREADY_EXIST) return helper.response_ok({'status': 'success'})
def _get_community_post(board_type, post_id): table_name = db.table.board(board_type) # if unknown board type if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) if board_type == 'music': # if board type is music, show with related music contracts and IPFS file. additional_columns = """ , '!music_contract', `mc`.* """ inner_join = """ LEFT JOIN `{}` `mc` ON (`mc`.`post_id` = `b`.`post_id`) """.format(db.table.MUSIC_CONTRACTS, db.table.IPFS_FILES) else: additional_columns = '' inner_join = '' post_query_statement = """ SELECT `b`.* {} FROM `{}` `b` {} WHERE `b`.`post_id` = :post_id AND `b`.`status` = :status """.format(additional_columns, table_name, inner_join) ipfs_files_query_statement = """ SELECT * FROM `ipfs_files` `if` INNER JOIN `music_contracts` `mc` ON (`mc`.`ipfs_file_id` = `if`.`file_id` OR `mc`.`ipfs_file_id` = `if`.`root_id`) WHERE `mc`.`post_id` = :post_id """ tags_statement = db.Statement( db.table.tags(board_type)).columns('name').where(post_id=post_id) with db.engine_rdonly.connect() as connection: post = connection.execute(text(post_query_statement), post_id=post_id, status='posted').fetchone() # if the post does not exist, if post is None: return helper.response_err(ERR.COMMON.NOT_EXIST) post = db.to_relation_model(post) if board_type == 'music': ipfs_files = db.to_relation_model_list( connection.execute(text(ipfs_files_query_statement), post_id=post_id)) post['music_contract'].update({'ipfs_file': ipfs_files}) tags = tags_statement.select(connection) post.update({'tags': [tag['name'] for tag in tags]}) return helper.response_ok(post)
def _upload_file(): """ uploads a file. (Only one file is allowed at once) """ user_id = request.user['user_id'] file_type = request.values.get('type') # if the number of files uploaded is not one if len(request.files) != 1: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) # if not support file type if file_type not in s3_policy: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) file = next(iter(request.files.values())) file_name = file.filename # read with content length size read_len = s3_policy[file_type]['file_size_limit'] + 1 file_data = file.read(read_len) # if the file size is too big if file.tell() == read_len: return helper.response_err(ERR.COMMON.FILE_SIZE_LIMIT_EXCEEDED) # check the number of file user uploaded for defending to upload too many files. upload_log_stmt = """ SELECT COUNT(*) AS `cnt` FROM `files` WHERE `user_id` = :user_id AND `created_at` > NOW() - INTERVAL 10 MINUTE AND `type` = :file_type """ profile_bucket = MuzikaS3Bucket(file_type=file_type) with db.engine_rdwr.connect() as connection: upload_cnt = connection.execute(text(upload_log_stmt), user_id=user_id, file_type=file_type).fetchone()['cnt'] # if the file uploaded too much, reject the request upload_cnt_limit = s3_policy[file_type].get('upload_count_limit') if upload_cnt_limit and upload_cnt >= upload_cnt_limit: return helper.response_err(ERR.COMMON.TOO_MANY_REQUEST) file = profile_bucket.put(connection=connection, name=file_name, value=file_data, user_id=user_id) if not file: return helper.response_err(ERR.COMMON.UPLOAD_FAIL) return helper.response_ok({'file_id': file['file_id']})
def _get_draft(): user_id = request.user['user_id'] board_type = request.args.get('boardType') with db.engine_rdonly.connect() as connect: draft_list = db.statement(db.table.POST_DRAFTS) \ .where(user_id=user_id, board_type=board_type) \ .select(connect) return helper.response_ok( [dict(draft_row) for draft_row in draft_list])
def _get_user_sign_message(address): """ Returns an user information by wallet address. If user(address) does not exist, give a random message for signing """ # if invalid address format, don't generate message if not check_address_format(address): return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) return helper.response_ok(get_message_for_user(address, always_new=True))
def _get_user_ont_sign_message(address): """ Returns an user information by ontology account address. If user(address) does not exist, give a random message for signing """ # if invalid address format, don't generate message if not check_ont_address_format(address): return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) return helper.response_ok(get_message_for_user(address, always_new=True, protocol='ont'))
def _change_user_profile(): json_form = request.get_json(force=True, silent=True) user_id = request.user['user_id'] profile_file_id = request.user.get('profile_file_id') if not isinstance(profile_file_id, int): return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) with db.engine_rdwr.connect() as connection: db.statement(db.table.USERS).set(profile_file_id=profile_file_id).where(user_id=user_id).update(connection) return helper.response_ok({'status': 'success'})
def _post_draft(): user_id = request.user['user_id'] board_type = request.args.get('boardType') data = request.get_json(force=True, silent=True) with db.engine_rdwr.connect() as connect: draft_id = db.statement( db.table.POST_DRAFTS).set(type=board_type, user_id=user_id, data=json.dumps(data), version=1).insert(connect).lastrowid return helper.response_ok(draft_id)
def _get_comments_likes(user_id, board_type): """ Gets an user's comment likes list """ table_name = db.table.comment_like(board_type) if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) with db.engine_rdonly.connect() as connection: comment_like_statement = db.Statement(table_name).where(user_id=user_id) return helper.response_ok(db.to_relation_model_list(comment_like_statement.select(connection)))
def _get_user(address): """ Returns an user information by wallet address. If user(address) does not exist, give a random message for signing """ # if invalid address format, don't generate message if not check_address_format(address): return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) with db.engine_rdonly.connect() as connection: user = db.statement(db.table.USERS).where(address=address).select(connection).fetchone() return helper.response_ok(db.to_relation_model(user))
def _change_user_info(column_name, max_len, min_len=0): json_form = request.get_json(force=True, silent=True) user_id = request.user['user_id'] value = json_form.get(column_name) if len(value) > max_len or len(value) < min_len: return helper.response_err(ERR.COMMON.TOO_LONG_PARAMETER) with db.engine_rdwr.connect() as connection: try: db.statement(db.table.USERS).set(**{column_name:value}).where(user_id=user_id).update(connection) except IntegrityError: return helper.response_err(ERR.COMMON.ALREADY_EXIST) return helper.response_ok({'status': 'success'})
def _get_board_posts(board_type): table_name = db.table.board(board_type) user_id = request.args.get('user_id') page = request.args.get('page', 1) # if unknown board type if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) from modules.pagination import Pagination from modules import board stmt = board.posts_query_stmt(board_type=board_type, user_id=user_id) if board_type == 'music': post_type = request.args.get('type') if isinstance(post_type, str): stmt.where(type=post_type) # only accept mined contract for users to show only purchasable contracts. stmt.where_advanced(db.table.MUSIC_CONTRACTS, status='success') def _to_relation_model(row): row = db.to_relation_model(row) if board_type == 'music': # since ipfs_file is related with music contracts, move ipfs_file row into music_contracts row. row['music_contract']['ipfs_file'] = [row['ipfs_file']] del row['ipfs_file'] return row with db.engine_rdonly.connect() as connection: fetch_query_str = stmt.select(connection, execute=False, is_count_query=False) count_query_str = stmt.select(connection, execute=False, is_count_query=True) order_query_str = "ORDER BY `{}`.`post_id` DESC".format( db.statement.get_table_alias(table_name)) return helper.response_ok( Pagination( connection=connection, fetch=fetch_query_str, count=count_query_str, order=order_query_str, current_page=page, fetch_params=stmt.fetch_params).get_result(_to_relation_model))
def _get_my_upload_board(board_type): """ :param board_type: 'sheet' or 'streaming' :return: BasePost[] """ user = request.user with db.engine_rdonly.connect() as connect: query = db.statement(db.table.board('music')) \ .inner_join(db.table.MUSIC_CONTRACTS, 'post_id') \ .inner_join((db.table.MUSIC_PAYMENTS, db.table.MUSIC_CONTRACTS), 'contract_address') \ .where(type=board_type) \ .where_advanced(db.table.MUSIC_PAYMENTS, buyer_address=user['address']) \ .order('post_id', 'desc').select(connect) return helper.response_ok([db.to_relation_model(row) for row in query])
def _put_draft(draft_id): user_id = request.user['user_id'] data = request.get_json(force=True, silent=True) with db.engine_rdwr.connect() as connect: draft_row = db.statement(db.table.POST_DRAFTS) \ .where(user_id=user_id, draft_id=draft_id).select(connect).fetchone() if draft_row is None: return helper.response_err(ERR.DRAFT.NOT_EXISTS) db.statement(db.table.POST_DRAFTS).set(data=json.dumps(data)).where( draft_id=draft_id).update(connect) return helper.response_ok("OK")
def _like_comment(board_type, comment_id): user_id = request.user['user_id'] board_table_name = db.table.board(board_type) comment_like_table_name = db.table.comment_like(board_type) if not board_table_name or not comment_like_table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) like_statement = db.Statement(comment_like_table_name).set(comment_id=comment_id, user_id=user_id) with db.engine_rdwr.begin() as connection: try: like_statement.insert(connection) except IntegrityError: return helper.response_err(ERR.COMMON.ALREADY_EXIST) return helper.response_ok({'status': 'success'})
def _delete_draft(draft_id): user_id = request.user['user_id'] with db.engine_rdwr.connect() as connect: draft_row = db.statement(db.table.POST_DRAFTS) \ .where(user_id=user_id, draft_id=draft_id) \ .select(connect).fetchone() if draft_row is None: return helper.response_err(ERR.DRAFT.NOT_EXISTS) elif draft_row['is_uploaded'] == 1: return helper.response_err(ERR.DRAFT.ALREADY_UPLOADED) else: db.statement( db.table.POST_DRAFTS).where(draft_id=draft_id).delete(connect) return helper.response_ok("OK")
def _cancel_like_post(board_type, post_id): user_id = request.user['user_id'] board_table_name = db.table.board(board_type) like_table_name = db.table.like(board_type) if not board_table_name or not like_table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) like_statement = db.Statement(like_table_name).where(post_id=post_id, user_id=user_id) with db.engine_rdwr.begin() as connection: deleted = like_statement.delete(connection).rowcount if deleted: return helper.response_ok({'status': 'success'}) else: return helper.response_err(ERR.COMMON.NOT_EXIST)
def _upload_paper(): """ Uploads a paper file from client. json form: { "hash": file hash string, "price": uint256, "encrypted": true | false, } Server downloads the paper file by its IPFS process from the client IPFS node and it creates a muzika contract for creating a paper in the block chain network. Server must have an IPFS node and it pins the object file for spreading the paper file. """ json_form = request.get_json(force=True, silent=True) file_hash = json_form.get('hash') wallet_address = request.user['address'] price = json_form.get('price') encrypted = json_form.get('encrypted', False) # check request json if not isinstance(file_hash, str) or not isinstance( price, int) or not isinstance(encrypted, bool): return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) # pin the file for spreading out the paper relay_ipfs = RelayIpfs() api = relay_ipfs.get_connection() # TODO : process if failed to pin (timeout problem) api.pin_add(file_hash) # create a paper contract web3 = get_web3() contract_handler = MuzikaContractHandler() paper_contract = contract_handler.get_contract(web3, 'MuzikaPaperContract') tx_hash = paper_contract.constructor( web3.toChecksumAddress(wallet_address), price, file_hash, '').transact() return helper.response_ok({'status': 'success'})
def _get_board_post_comments(board_type, post_id): comment_table_name = db.table.comment(board_type) board_table_name = db.table.board(board_type) page = request.args.get('page', 1) # if unknown board type if not comment_table_name or not board_table_name: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) fetch_query_str = """ SELECT `c`.*, '!user', `u`.* FROM `{}` `c` INNER JOIN `{}` `b` ON (`c`.`post_id` = `b`.`post_id` AND `c`.`parent_comment_id` IS NULL) INNER JOIN `users` `u` ON (`u`.`user_id` = `c`.`user_id`) WHERE `c`.`post_id` = :post_id AND `c`.`status` = :post_status """.format(comment_table_name, board_table_name) count_query_str = """ SELECT COUNT(*) AS `cnt` FROM `{}` `c` INNER JOIN `{}` `b` ON (`c`.`post_id` = `b`.`post_id` AND `c`.`parent_comment_id` IS NULL) WHERE `c`.`post_id` = :post_id AND `c`.`status` = :post_status """.format(comment_table_name, board_table_name) order_query_str = "ORDER BY `c`.`created_at` DESC" with db.engine_rdonly.connect() as connection: from modules.pagination import Pagination return helper.response_ok( Pagination(connection=connection, fetch=fetch_query_str, count=count_query_str, order=order_query_str, current_page=page, fetch_params={ 'post_id': post_id, 'post_status': 'posted' }).get_result(db.to_relation_model))
def _delete_board_comment(board_type, comment_id): user_id = request.user['user_id'] table_name = db.table.comment(board_type) # if unknown board type if not table_name: return helper.response_err(ERR.COMMON.INVALID_REQUEST_BODY) statement = db.Statement(table_name).set(status='deleted')\ .where(user_id=user_id, comment_id=comment_id, status='posted') with db.engine_rdwr.connect() as connection: deleted = statement.update(connection).rowcount if not deleted: return helper.response_err(ERR.COMMON.AUTHENTICATION_FAILED) return helper.response_ok({'status': 'success'})
def _post_board_subcomment(board_type, parent_comment_id): json_form = request.get_json(force=True, silent=True) content = json_form.get('content') user_id = request.user['user_id'] if not isinstance(content, str) or not isinstance(parent_comment_id, int): return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) table_name = db.table.comment(board_type) # if unknown board type if not table_name: return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) statement = db.Statement(table_name).set( user_id=user_id, parent_comment_id=parent_comment_id, content=content) parent_update_statement = """ UPDATE `{}` SET `reply_count` = `reply_count` + 1 WHERE `comment_id` = :parent_comment_id LIMIT 1 """.format(table_name) with db.engine_rdwr.begin() as connection: try: comment_id = statement.insert(connection).lastrowid except IntegrityError: # if failed to insert return helper.response_err(ER.INVALID_REQUEST_BODY, ER.INVALID_REQUEST_BODY_MSG) connection.execute(text(parent_update_statement), parent_comment_id=parent_comment_id) return helper.response_ok({'comment_id': comment_id})