def log_in_route(request): """ Log in user. """ db_conn = request['db_conn'] name = request['params'].get('name') or '' name = name.lower().strip() user = get_user({'name': name}, db_conn) if not user: user = get_user({'email': request['params'].get('name')}, db_conn) if not user: return 404, { 'errors': [{ 'name': 'name', 'message': c('no_user'), }], 'ref': 'FYIPOI8g2nzrIEcJYSDAfmti' } real_encrypted_password = user['password'] given_password = request['params'].get('password') if not is_password_valid(real_encrypted_password, given_password): return 400, { 'errors': [{ 'name': 'password', 'message': c('no_match'), }], 'ref': 'UwCRydZ7Agi7LYKv9c1y07ft' } return _log_in(user)
def log_in_route(request): """ Log in user. """ name = request['params'].get('name') or '' name = name.lower() user = User.get(name=name) if not user: user = User.get(email=request['params'].get('name')) if not user: return 404, { 'errors': [{ 'name': 'name', 'message': c('no_user'), }], 'ref': 'FYIPOI8g2nzrIEcJYSDAfmti' } if not user.is_password_valid(request['params'].get('password')): return 400, { 'errors': [{ 'name': 'password', 'message': c('no_match'), }], 'ref': 'UwCRydZ7Agi7LYKv9c1y07ft' } return _log_in(user)
def log_in_route(request): """ Log in user. """ db_conn = request['db_conn'] name = request['params'].get('name') or '' name = name.lower().strip() user = get_user(db_conn, {'name': name}) if not user: user = get_user(db_conn, {'email': name}) if not user: return 404, { 'errors': [{ 'name': 'name', 'message': c('no_user'), 'ref': 'dfhMHDFbT42CmRRmN14gdA', }], } real_encrypted_password = user['password'] given_password = request['params'].get('password') if not is_password_valid(real_encrypted_password, given_password): return 400, { 'errors': [{ 'name': 'password', 'message': c('no_match'), 'ref': 'DTarUzzsSLKarq-uIsXkFQ', }], } return _log_in(user)
def is_required(value): """ Ensure the value is present. """ if value is None: return c('required') if isinstance(value, str) and value == '': return c('required')
def is_list_of_strings(value): """ Ensure the number is a list of strings. """ if value is None: return if not isinstance(value, list): return c('list') for v in value: if not isinstance(v, str): return c('string')
def is_list_of_uuids(value): """ Ensure the value is a list of UUIDs. """ if value is None: return if not isinstance(value, list): return c('list') for entry in value: if not isinstance(entry, uuid.UUID): return c('uuid')
def is_list_of_strings(value): """ Ensure the number is a list of strings. """ if value is None: return if not isinstance(value, list): return c('list') for entry in value: if not isinstance(entry, str): return c('string')
def is_required(value): """ Ensure the value is present. """ if value is None: return c('required')
def has_min_length(value, ln): """ Ensure the given value is a minimum length. """ if value is None: return if not value or len(value) < ln: return c('minlength').replace('{length}', str(ln))
def has_min_length(value, leng): """ Ensure the given value is a minimum length. """ if value is None: return if not value or len(value) < leng: return c('minlength').replace('{length}', str(leng))
def is_email(value): """ Ensure the given value is formatted as an email. """ if value is None: return if not re.match(r'\S+@\S+\.\S+', value): return c('email')
def is_url(value): """ Ensure the given value is formatted as an URL. """ if value is None: return if not re.match(r'^(http(s)?:)?//[^.]+\..+$', value): return c('url')
def is_list(value): """ Ensure the given value is a list. """ if value is None: return if not isinstance(value, list): return c('list')
def is_dict(value): """ Ensure the given value is a dict. """ if value is None: return if not isinstance(value, dict): return c('dict')
def is_language(value): """ Entity must be ISO 639-1 code. """ if value is None: return if not isinstance(value, str) or len(value) != 2: return c('language')
def is_boolean(value): """ Ensure the given value is a boolean. """ if value is None: return if not isinstance(value, bool): return c('boolean')
def is_string_or_number(value): """ Ensure the given value is a string or number. """ if value is None: return if not isinstance(value, (str, int, float, complex)): return c('string_or_number')
def is_one_of(value, *options): """ Ensure the value is within an enumerated set. """ if value is None: return if value not in options: str_options = [str(o) for o in options] return (c('options').replace('{options}', ', '.join(str_options)))
def is_string(value): """ Ensure the given value is a string. """ if value is None: return if not isinstance(value, str): return c('string')
def is_number(value): """ Ensure the given value is a number. """ if value is None: return if not isinstance(value, (int, float)): return c('number')
def is_integer(value): """ Ensure the given value is a integer. """ if value is None: return if not isinstance(value, int): return c('integer')
def has_max_length(value, ln): """ Ensure the given value is a maximum length. """ if value is None: return if not value or len(value) > ln: return c('maxlength').replace('{length}', str(ln))
def is_datetime(value): """ Ensure the given value is a datetime. """ if value is None: return if not isinstance(value, datetime): return c('datetime')
def log_in_route(request): """ Log in user. """ db_conn = request["db_conn"] name = request["params"].get("name") or "" name = name.lower().strip() user = get_user({"name": name}, db_conn) if not user: user = get_user({"email": request["params"].get("name")}, db_conn) if not user: return 404, {"errors": [{"name": "name", "message": c("no_user")}], "ref": "FYIPOI8g2nzrIEcJYSDAfmti"} real_encrypted_password = user["password"] given_password = request["params"].get("password") if not is_password_valid(real_encrypted_password, given_password): return 400, {"errors": [{"name": "password", "message": c("no_match")}], "ref": "UwCRydZ7Agi7LYKv9c1y07ft"} return _log_in(user)
def is_uuid(value): """ Ensure the given value is a UUID. """ if value is None: return if not isinstance(value, uuid.UUID): return c('uuid')
def has_correct_options(options): """ Ensure the list of options has at least one correct option. """ has_correct = False for option in options: if option.get('correct') is True: has_correct = True if not has_correct: return c('error_need_correct')
def is_one_of(value, *options): """ Ensure the value is within an enumerated set. """ if value is None: return if value not in options: str_options = [str(o) for o in options] return (c('options') .replace('{options}', ', '.join(str_options)))
def is_language(value): """ Entity must be BPC 47 code. https://tools.ietf.org/rfc/bcp/bcp47.txt """ if value is None: return if not isinstance(value, str) or len(value) != 2: return c('language')
def _(data, field_name, field_schema, prefix): if ('unique' not in field_schema or data.get(field_name) is None): return query = (r.table(schema['tablename']) .filter(r.row[field_name] == data.get(field_name)) .filter(r.row['id'] != data['id'])) if len(list(query.run(db_conn))) > 0: errors.append({ 'name': prefix + field_name, 'message': c('unique'), })
def get_topic_route(request, topic_id): """ Get a topic """ db_conn = request['db_conn'] topic = get_topic(db_conn, {'id': topic_id}) if not topic: return 404, { 'errors': [{ 'name': 'topic_id', 'message': c('no_topic'), }], 'ref': 'o5V4uBFXQC6WNeyKrhn5kA', } return 200, {'topic': deliver_topic(topic)}
def get_email_token(user, send_email=True): """ Create an email token for the user to reset their password. """ token = uniqid() redis.setex( 'user_password_token_{id}'.format(id=user['id']), # key 60 * 10, # time bcrypt.encrypt(user['id'] + token) # value ) if send_email: send_mail(subject='Sagefy - Reset Password', recipient=user['email'], body=c('change_password_url').replace( '{url}', '%spassword?id=%s&token=%s' % ('https://sagefy.org/', user['id'], token))) return token
def get_email_token(self, send_email=True): """ Create an email token for the user to reset their password. """ token = uniqid() redis.setex( "user_password_token_{id}".format(id=self["id"]), # key 60 * 10, # time bcrypt.encrypt(self["id"] + token), # value ) if send_email: send_mail( subject="Sagefy - Reset Password", recipient=self["email"], body=c("change_password_url").replace( "{url}", "%spassword?id=%s&token=%s" % ("https://sagefy.org/", self["id"], token) ), ) return token
def get_email_token(user, send_email=True): """ Create an email token for the user to reset their password. """ token = uniqid() redis.setex( 'user_password_token_{id}'.format(id=user['id']), # key 60 * 10, # time bcrypt.encrypt(user['id'] + token) # value ) if send_email: send_mail( subject='Sagefy - Reset Password', recipient=user['email'], body=c('change_password_url').replace( '{url}', '%spassword?id=%s&token=%s' % ('https://sagefy.org/', user['id'], token) ) ) return token
def get_body(self): """ Get the copy associated with this notice. """ return c('notice_' + self['kind']).format(**self['data'])
def create_post_route(request, topic_id): """ Create a new post on a given topic. Proposal: must include entity (card, unit, or set) information. Vote: must refer to a valid proposal. """ db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) topic = get_topic({'id': topic_id}, db_conn) if not topic: return 404, { 'errors': [{ 'name': 'topic_id', 'message': c('no_topic'), }], 'ref': 'PCSFCxsJtnlP0x9WzbPoKcwM', } # ## STEP 1) Create post (and entity) instances post_data = request['params'].get('post') if not post_data: return 400, { 'errors': [{ 'name': 'post', 'message': 'Missing post data.', }], 'ref': 'ykQpZwJKq54MTCxgkx0p6baW' } post_data = omit(post_data, ( 'id', 'created', 'modified', )) post_data['user_id'] = current_user['id'] post_data['topic_id'] = topic_id post_ = instance_post_facade(post_data) post_kind = post_['kind'] if post_kind == 'proposal': entity = instance_new_entity(request['params']) entity_kind = get_kind(request['params']) post_['entity_version'] = { 'id': entity['id'], 'kind': entity_kind, } # ## STEP 2) Validate post (and entity) instances errors = prefix_error_names('post.', post_.validate(db_conn)) if post_kind == 'proposal': errors = (errors + prefix_error_names('entity.', entity.validate(db_conn))) if len(errors): return 400, {'errors': errors, 'ref': 'tux33ztgFj9ittSpS7WKIkq7'} # ## STEP 3) Save post (and entity) post_.save(db_conn) if post_kind == 'proposal': entity.save(db_conn) # ## STEP 4) Add author as a follower insert_follow( { 'user_id': current_user['id'], 'entity': { 'id': topic['id'], 'kind': 'topic', } }, db_conn) # TODO-2 also follow the entity # ## STEP 5) Make updates based on proposal / vote status if post_kind == 'proposal': update_entity_status(db_conn, post_) if post_kind == 'vote': proposal = Proposal.get(db_conn, id=post_['replies_to_id']) update_entity_status(db_conn, proposal) # ## STEP 6) Send notices if post_kind == 'proposal': send_notices(db_conn, entity_id=topic['entity']['id'], entity_kind=topic['entity']['kind'], notice_kind='create_proposal', notice_data={ 'user_name': current_user['name'], 'topic_name': topic['name'], 'entity_kind': topic['entity']['kind'], 'entity_name': topic['entity']['id'], }) # ## STEP 7) Return response return 200, {'post': post_.deliver()}
def get_posts_route(request, topic_id): """ Get a reverse chronological listing of posts for given topic. Includes topic meta data and posts (or proposals or votes). Paginates. """ db_conn = request['db_conn'] # Is the topic valid? topic = get_topic({'id': topic_id}, db_conn) if not topic: return 404, { 'errors': [{ 'name': 'topic_id', 'message': c('no_topic'), }], 'ref': 'pgnNbqSP1VUWkOYq8MVGPrSS', } # Pull the entity entity_kind = topic['entity']['kind'] entity = get_latest_accepted(db_conn, entity_kind, topic['entity']['id']) # Pull all kinds of posts posts = get_posts_facade(db_conn, limit=request['params'].get('limit') or 10, skip=request['params'].get('skip') or 0, topic_id=topic_id) # For proposals, pull up the proposal entity version # ...then pull up the previous version # ...make a diff between the previous and the proposal entity version diffs = {} entity_versions = {} for post_ in posts: if post_['kind'] == 'proposal': entity_version = entity_versions[post_['id']] = get_version( db_conn, post_['entity_version']['kind'], post_['entity_version']['id']) previous_version = get_version(db_conn, post_['entity_version']['kind'], entity_version['previous_id']) if previous_version: diffs[post_['id']] = object_diff(previous_version.deliver(), entity_version.deliver()) # TODO-2 SPLITUP create new endpoint for this instead users = {} for post_ in posts: user_id = post_['user_id'] if user_id not in users: user = get_user({'id': user_id}, db_conn) if user: users[user_id] = { 'name': user['name'], 'avatar': get_avatar(user['email'], 48), } # TODO-2 SPLITUP create new endpoints for these instead output = { 'topic': deliver_topic(topic), 'posts': [p.deliver() for p in posts], 'entity_versions': {p: ev.deliver('view') for p, ev in entity_versions.items()}, # 'diffs': diffs, TODO-2 this causes a circular dependency 'users': users, } if entity: output[entity_kind] = entity.deliver() return 200, output
def create_post_route(request, topic_id): """ Create a new post on a given topic. Proposal: must include entity (card, unit, or set) information. Vote: must refer to a valid proposal. """ current_user = get_current_user(request) if not current_user: return abort(401) topic = Topic.get(id=topic_id) if not topic: return 404, { 'errors': [{ 'name': 'topic_id', 'message': c('no_topic'), }], 'ref': 'PCSFCxsJtnlP0x9WzbPoKcwM', } # ## STEP 1) Create post (and entity) instances post_data = request['params'].get('post') if not post_data: return 400, { 'errors': [{ 'name': 'post', 'message': 'Missing post data.', }], 'ref': 'ykQpZwJKq54MTCxgkx0p6baW' } post_data = omit(post_data, ('id', 'created', 'modified',)) post_data['user_id'] = current_user['id'] post_data['topic_id'] = topic_id post_ = instance_post_facade(post_data) post_kind = post_['kind'] if post_kind == 'proposal': entity = instance_new_entity(request['params']) entity_kind = get_kind(request['params']) post_['entity_version'] = { 'id': entity['id'], 'kind': entity_kind, } # ## STEP 2) Validate post (and entity) instances errors = prefix_error_names('post.', post_.validate()) if post_kind == 'proposal': errors = errors + prefix_error_names('entity.', entity.validate()) if len(errors): return 400, { 'errors': errors, 'ref': 'tux33ztgFj9ittSpS7WKIkq7' } # ## STEP 3) Save post (and entity) post_.save() if post_kind == 'proposal': entity.save() # ## STEP 4) Add author as a follower Follow.insert({ 'user_id': current_user['id'], 'entity': { 'id': topic['id'], 'kind': 'topic', } }) # TODO-2 also follow the entity # ## STEP 5) Make updates based on proposal / vote status if post_kind == 'proposal': update_entity_status(post_) if post_kind == 'vote': proposal = Proposal.get(id=post_['replies_to_id']) update_entity_status(proposal) # ## STEP 6) Return response return 200, {'post': post_.deliver()}
def get_posts_route(request, topic_id): """ Get a reverse chronological listing of posts for given topic. Includes topic meta data and posts (or proposals or votes). Paginates. """ # Is the topic valid? topic = Topic.get(id=topic_id) if not topic: return 404, { 'errors': [{ 'name': 'topic_id', 'message': c('no_topic'), }], 'ref': 'pgnNbqSP1VUWkOYq8MVGPrSS', } # Pull the entity entity_kind = topic['entity']['kind'] entity = get_latest_accepted(entity_kind, topic['entity']['id']) # Pull all kinds of posts posts = get_posts_facade( limit=request['params'].get('limit') or 10, skip=request['params'].get('skip') or 0, topic_id=topic_id ) # For proposals, pull up the proposal entity version # ...then pull up the previous version # ...make a diff between the previous and the proposal entity version diffs = {} entity_versions = {} for post_ in posts: if post_['kind'] == 'proposal': entity_version = entity_versions[post_['id']] = get_version( post_['entity_version']['kind'], post_['entity_version']['id'] ) previous_version = get_version( post_['entity_version']['kind'], entity_version['previous_id'] ) if previous_version: diffs[post_['id']] = object_diff(previous_version.deliver(), entity_version.deliver()) # TODO-2 SPLITUP create new endpoint for this instead users = {} for post_ in posts: user_id = post_['user_id'] if user_id not in users: user = User.get(id=user_id) if user: users[user_id] = { 'name': user['name'], 'avatar': user.get_avatar(48) } # TODO-2 SPLITUP create new endpoints for these instead output = { 'topic': topic.deliver(), 'posts': [p.deliver() for p in posts], 'entity_versions': { p: ev.deliver() for p, ev in entity_versions.items() }, # 'diffs': diffs, TODO-2 this causes a circular dependency 'users': users, } if entity: output[entity_kind] = entity.deliver() return 200, output
def index_route(request): """ View a documentation page. """ return 200, {'message': c('welcome')}
def get_notice_body(notice): """ Get the copy associated with this notice. """ return c('notice_' + notice['kind']).format(**notice['data'])
def is_score(val): if val > 1 or val < 0: return c('number')