import uuid import simplejson as json import datetime import redis # used for collections from utility.hmac import hmac_creation from utility.logger import getLogger logger = getLogger(__name__) def get_redis_conn(): Redis = redis.StrictRedis(port=6379) return Redis Redis = get_redis_conn() def is_redis_available(): try: Redis.ping() except: return False return True def load_json_from_redis(item_list, column_value): return json.loads(item_list[column_value]) def get_user_id(column_name, column_value): user_list = Redis.hgetall("users") key_list = [] for key in user_list: user_ob = json.loads(user_list[key]) if column_name in user_ob and user_ob[column_name] == column_value: return key return None def get_user_by_unique_column(column_name, column_value): item_details = None user_list = Redis.hgetall("users") if column_name != "user_id": for key in user_list: user_ob = json.loads(user_list[key]) if column_name in user_ob and user_ob[column_name] == column_value: item_details = user_ob else: item_details = load_json_from_redis(user_list, column_value) return item_details def get_users_like_unique_column(column_name, column_value): """Like previous function, but this only checks if the input is a subset of a field and can return multiple results """ matched_users = [] if column_value != "": user_list = Redis.hgetall("users") if column_name != "user_id": for key in user_list: user_ob = json.loads(user_list[key]) if "user_id" not in user_ob: set_user_attribute(key, "user_id", key) user_ob["user_id"] = key if column_name in user_ob: if column_value in user_ob[column_name]: matched_users.append(user_ob) else: matched_users.append(load_json_from_redis(user_list, column_value)) return matched_users def set_user_attribute(user_id, column_name, column_value): user_info = json.loads(Redis.hget("users", user_id)) user_info[column_name] = column_value Redis.hset("users", user_id, json.dumps(user_info)) def get_user_collections(user_id): collections = None collections = Redis.hget("collections", user_id) if collections: return json.loads(collections) else: return [] def save_user(user, user_id): Redis.hset("users", user_id, json.dumps(user)) def save_collections(user_id, collections_ob): Redis.hset("collections", user_id, collections_ob) def save_verification_code(user_email, code): Redis.hset("verification_codes", code, user_email) def check_verification_code(code): email_address = None user_details = None email_address = Redis.hget("verification_codes", code) if email_address: user_details = get_user_by_unique_column( 'email_address', email_address) if user_details: return user_details else: return None else: return None def get_user_groups(user_id): # ZS: Get the groups where a user is an admin or a member and # return lists corresponding to those two sets of groups admin_group_ids = [] # ZS: Group IDs where user is an admin user_group_ids = [] # ZS: Group IDs where user is a regular user groups_list = Redis.hgetall("groups") for key in groups_list: try: group_ob = json.loads(groups_list[key]) group_admins = set([this_admin.encode('utf-8') if this_admin else None for this_admin in group_ob['admins']]) group_members = set([this_member.encode('utf-8') if this_member else None for this_member in group_ob['members']]) if user_id in group_admins: admin_group_ids.append(group_ob['id']) elif user_id in group_members: user_group_ids.append(group_ob['id']) else: continue except: continue admin_groups = [] user_groups = [] for the_id in admin_group_ids: admin_groups.append(get_group_info(the_id)) for the_id in user_group_ids: user_groups.append(get_group_info(the_id)) return admin_groups, user_groups def get_group_info(group_id): group_json = Redis.hget("groups", group_id) group_info = None if group_json: group_info = json.loads(group_json) return group_info def get_group_by_unique_column(column_name, column_value): """ Get group by column; not sure if there's a faster way to do this """ matched_groups = [] all_group_list = Redis.hgetall("groups") for key in all_group_list: group_info = json.loads(all_group_list[key]) # ZS: Since these fields are lists, search in the list if column_name == "admins" or column_name == "members": if column_value in group_info[column_name]: matched_groups.append(group_info) else: if group_info[column_name] == column_value: matched_groups.append(group_info) return matched_groups def get_groups_like_unique_column(column_name, column_value): """Like previous function, but this only checks if the input is a subset of a field and can return multiple results """ matched_groups = [] if column_value != "": group_list = Redis.hgetall("groups") if column_name != "group_id": for key in group_list: group_info = json.loads(group_list[key]) # ZS: Since these fields are lists, search in the list if column_name == "admins" or column_name == "members": if column_value in group_info[column_name]: matched_groups.append(group_info) else: if column_name in group_info: if column_value in group_info[column_name]: matched_groups.append(group_info) else: matched_groups.append(load_json_from_redis(group_list, column_value)) return matched_groups def create_group(admin_user_ids, member_user_ids=[], group_name="Default Group Name"): group_id = str(uuid.uuid4()) new_group = { "id": group_id, "admins": admin_user_ids, "members": member_user_ids, "name": group_name, "created_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'), "changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') } Redis.hset("groups", group_id, json.dumps(new_group)) return new_group def delete_group(user_id, group_id): # ZS: If user is an admin of a group, remove it from the groups hash group_info = get_group_info(group_id) if user_id in group_info["admins"]: Redis.hdel("groups", group_id) return get_user_groups(user_id) else: None # ZS "admins" is just to indicate whether the users should be added to # the groups admins or regular users set def add_users_to_group(user_id, group_id, user_emails=[], admins=False): group_info = get_group_info(group_id) # ZS: Just to make sure that the user is an admin for the group, # even though they shouldn't be able to reach this point unless # they are if user_id in group_info["admins"]: if admins: group_users = set(group_info["admins"]) else: group_users = set(group_info["members"]) for email in user_emails: user_id = get_user_id("email_address", email) group_users.add(user_id) if admins: group_info["admins"] = list(group_users) else: group_info["members"] = list(group_users) group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime( '%b %d %Y %I:%M%p') Redis.hset("groups", group_id, json.dumps(group_info)) return group_info else: return None # ZS: User type is because I assume admins can remove other admins def remove_users_from_group(user_id, users_to_remove_ids, group_id, user_type="members"): group_info = get_group_info(group_id) if user_id in group_info["admins"]: users_to_remove_set = set(users_to_remove_ids) # ZS: Make sure an admin can't remove themselves from a group, # since I imagine we don't want groups to be able to become # admin-less if user_type == "admins" and user_id in users_to_remove_set: users_to_remove_set.remove(user_id) group_users = set(group_info[user_type]) group_users -= users_to_remove_set group_info[user_type] = list(group_users) group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime( '%b %d %Y %I:%M%p') Redis.hset("groups", group_id, json.dumps(group_info)) def change_group_name(user_id, group_id, new_name): group_info = get_group_info(group_id) if user_id in group_info["admins"]: group_info["name"] = new_name Redis.hset("groups", group_id, json.dumps(group_info)) return group_info else: return None def get_resources(): resource_list = Redis.hgetall("resources") return resource_list def get_resource_id(dataset, trait_id=None): resource_id = False if dataset.type == "Publish": if trait_id: resource_id = hmac_creation("{}:{}:{}".format( 'dataset-publish', dataset.id, trait_id)) elif dataset.type == "ProbeSet": resource_id = hmac_creation( "{}:{}".format('dataset-probeset', dataset.id)) elif dataset.type == "Geno": resource_id = hmac_creation( "{}:{}".format('dataset-geno', dataset.id)) return resource_id def get_resource_info(resource_id): resource_info = Redis.hget("resources", resource_id) if resource_info: return json.loads(resource_info) else: return None def add_resource(resource_info, update=True): if 'trait' in resource_info['data']: resource_id = hmac_creation('{}:{}:{}'.format( str(resource_info['type']), str( resource_info['data']['dataset']), str(resource_info['data']['trait']))) else: resource_id = hmac_creation('{}:{}'.format( str(resource_info['type']), str(resource_info['data']['dataset']))) if update or not Redis.hexists("resources", resource_id): Redis.hset("resources", resource_id, json.dumps(resource_info)) return resource_info def add_access_mask(resource_id, group_id, access_mask): the_resource = get_resource_info(resource_id) the_resource['group_masks'][group_id] = access_mask Redis.hset("resources", resource_id, json.dumps(the_resource)) return the_resource def change_resource_owner(resource_id, new_owner_id): the_resource = get_resource_info(resource_id) the_resource['owner_id'] = new_owner_id Redis.delete("resource") Redis.hset("resources", resource_id, json.dumps(the_resource))