class UserManager: def __init__(self, redis_manager): self.redis = redis_manager self.requests_prefix = "req/{}" self.emails = RedisSet('users') self.displayNames = RedisSet('displayNames') def create_user(self, email): session_id = self.redis.get_value("usersession: {}".format(email)) user_data = RedisHash(email).to_dict() if session_id and user_data: return User(user_data['school'], email, user_data['displayName'], session_id) return None def store_user_in_redis(self, email, password_hash, school, display_name): self.emails.add(email) self.displayNames.add(display_name) user_data = {'school': school, 'displayName': display_name} RedisHash(email).update(user_data) self.redis.set("hash: {}".format(email), password_hash) def made_request(self, email, request_id): return RedisSet("req/{}".format(email)).add([request_id]) def remove_request(self, email, request_id): return RedisSet("req/{}".format(email)).remove(request_id) def made_post(self, email, post_id): return RedisSet("posts/{}".format(email)).add([post_id]) def created_content(self, email, content_id): return RedisSet("content/{}".format(email)).add(content_id)
def __init__(self): self.displayNames = RedisSet("displayNames") self.nouns = [] self.adjectives = [] with open("resources/nouns.txt", "r") as f: self.nouns = [line.strip('\n') for line in f if line.strip('\n')] with open("resources/adjectives_names.txt", "r") as f: self.adjectives = [line.strip('\n') for line in f if line]
def __init__(self, redis_values, post_store, upload_store, listing_store, reply_store, auth_manager): self.redis = redis_values self.post = post_store self.upload = upload_store self.listing = listing_store self.reply = reply_store self.auth = auth_manager self.request_ids = RedisSet("requests")
def create_listing(self, request): """ Create a listing for a school's page. :param request: request data to promote to listing :return: listing ID if successful, otherwise None """ school_id = request["sid"] user_email = request["uid"] # get new listing_id listing_id = self.name_provider.generate_listing_id( user_email, school_id) # upload files new_upload_id = self.name_provider.generate_upload_id(listing_id) filepaths = self.upload.promote_uploads(request["upload_id"], new_upload_id) RedisSet(new_upload_id).add(filepaths) # store listing data in redis return super().make_content( listing_id, { "sid": school_id, "title": request["title"], "course": request["course"], "kind": request["kind"], "uid": user_email, "email": request["email"], "upload_id": new_upload_id, "time": request["time"] })
def get_posts(self, school_id): """ Get all existing posts for school. :param school_id: ID of school :return: dict containing all posts for school """ posts = {} post_set_key = self.name_provider.set_names.post(school_id) for post_id in RedisSet(post_set_key).values(): posts[post_id] = super().get_content(post_id) app.logger.debug("fetched {} posts for sid {}".format(len(posts), school_id)) return posts
def get_replies(self, content_id): """ Get all existing replies for content with given ID :param content_id: ID of content :return: dict containing all replies """ replies = {} reply_set_key = self.name_provider.set_names.reply(content_id) for reply_id in RedisSet(reply_set_key).values(): replies[reply_id] = super().get_content(reply_id) app.logger.debug("fetched {} replies for content {}".format( len(replies), content_id)) return replies
def generate(self, prefix, email, set_name): """ Generate unique ID, recursively regenerate on collision. Store unique ID in redis set named set_name. :param email: email of user (used for creating hash) :param prefix: prefix to give to ID :param set_name: name of Redis set to look for ID collisions :return: string containing ID """ identifier = self._create_id_hash(prefix, email) # ensure id is unique (no collisions) if RedisSet(set_name).add([identifier]) == 0: return self.generate(prefix, email, set_name) return identifier
def get_listings(self, school_id): """ Get all existing listings for school. :param school_id: ID of school to get listings from :return: dict containing all listing data for school """ listings = {} listing_set_key = self.name_provider.set_names.listing(school_id) for listing_id in RedisSet(listing_set_key).values(): try: listings[listing_id] = self.get_listing(listing_id) except Exception as e: app.logger.error("failed to fetch listing with id {}\n{}", listing_id, str(e)) app.logger.debug("fetched {} listings for sid {}".format( len(listings), school_id)) return listings
class UserCache: def __init__(self): self.name_provider = NameProvider() self.cached = RedisSet(self.name_provider.set_names.cached_ips) def is_cached(self, ip_address): """ Returns whether or not IP address is cached :param ip_address: IP address to check :return: boolean indicating if IP is cached """ key = self._get_key_for(ip_address) return self.cached.exists(key) def get(self, ip_address): """ Returns cached data for IP address :param ip_address: IP address to get cached data for :return: dict containing cached data """ key = self._get_key_for(ip_address) return RedisHash(key).to_dict() def set(self, ip_address, data): """ Sets cached data for given IP address :param ip_address: IP address to set cached data for :param data: data to set in cache """ key = self._get_key_for(ip_address) return RedisHash(key).update(data) def delete(self, ip_address, key_to_delete): """ Removes (key, value) pair from IP address hash :param ip_address: IP address of cached data :param key_to_delete: key to delete """ ip_address_key = self._get_key_for(ip_address) return RedisHash(ip_address_key).delete(key_to_delete) def _get_key_for(self, ip_address): """ Returns redis key for ip address cached data """ return "{}{}".format(self.name_provider.prefixes.ip, ip_address)
class UsernameGenerator: def __init__(self): self.displayNames = RedisSet("displayNames") self.nouns = [] self.adjectives = [] with open("resources/nouns.txt", "r") as f: self.nouns = [line.strip('\n') for line in f if line.strip('\n')] with open("resources/adjectives_names.txt", "r") as f: self.adjectives = [line.strip('\n') for line in f if line] def get_username(self): return random.choice(self.adjectives) + random.choice(self.nouns) def get_usernames_in_bulk(self, count=50): usernames = [] while len(usernames) < count: username = self.get_username() if not self.displayNames.exists(username): usernames += [username] return usernames
def request_listing(self, form_data, file): """ Request to create a listing in a school's page. :param form_data: raw form data submitted by user :param file: flask file object for uploaded PDF document :return: request ID if successful, otherwise None """ if not super().validate_data(form_data): return False # get new request_id request_id = self.name_provider.generate_request_id(super().user_email) if request_id is None: return False # upload files upload_id = self.name_provider.generate_upload_id(request_id) filepaths, numPages = self.upload.add_file_to_listing(file, upload_id) if len(filepaths) == 0: app.logger.error("Error: no filepaths were created") return False if RedisSet(upload_id).add(filepaths) != len(filepaths): app.logger.error( "Error: not all filepaths were added to set {}".format( upload_id)) return False # store request data in redis return super().request_content( request_id, { "sid": self.school.get_school_id(form_data["school"]), "title": form_data["title"], "course": form_data["cid"], "kind": form_data["kind"], "uid": super().display_name, "email": super().user_email, "upload_id": upload_id, "numPages": numPages, "requestId": request_id })
def made_request(self, email, request_id): return RedisSet("req/{}".format(email)).add([request_id])
def __init__(self): self.name_provider = NameProvider() self.cached = RedisSet(self.name_provider.set_names.cached_ips)
def created_content(self, email, content_id): return RedisSet("content/{}".format(email)).add(content_id)
def made_post(self, email, post_id): return RedisSet("posts/{}".format(email)).add([post_id])
def remove_request(self, email, request_id): return RedisSet("req/{}".format(email)).remove(request_id)
def __init__(self, redis_manager): self.redis = redis_manager self.requests_prefix = "req/{}" self.emails = RedisSet('users') self.displayNames = RedisSet('displayNames')
class RequestStore: """ Class for managing request data. A request is created each time a user wants to submit content to GradeTip. Once that content is approved by moderators, the request is deleted and replaced by the corresponding content data type. """ def __init__(self, redis_values, post_store, upload_store, listing_store, reply_store, auth_manager): self.redis = redis_values self.post = post_store self.upload = upload_store self.listing = listing_store self.reply = reply_store self.auth = auth_manager self.request_ids = RedisSet("requests") def get_all_requests(self): """ Gets all requests submitted to GradeTip. :return: dict containing request_ids as keys and request data as values """ if not request.headers or not self.auth.validate_headers( request.headers): return jsonify({}), 404 requests = {} for request_id in self.request_ids.values(): request_data = self.get_request(request_id) if request_data.get("requestType") == "listing": request_data["preview"] = self.upload.get_preview_from_listing( request_data["upload_id"]) del request_data["upload_id"] app.logger.debug("request: {}".format(request_data)) requests[request_id] = request_data app.logger.debug("fetched {} requests".format(len(requests))) return requests def delete_request(self, request_id): """ Deletes request and relevant request data. :param request_id: ID of request to be deleted :return: boolean indicating success of operation """ app.logger.info("deleting request with id: {}".format(request_id)) id_deleted = self.request_ids.remove(request_id) hash_deleted = self.redis.remove(request_id) return id_deleted and hash_deleted def pop_request(self, request_id): """ Retrieves request with ID request_id and then deletes that request. :param request_id: ID of request to find :return: dict containing request data """ request_data = self.get_request(request_id) self.delete_request(request_id) return request_data def get_request(self, request_id): """ Retrieves request with ID request_id. :param request_id: ID of request to find :return: dict containing request data """ app.logger.debug("fetching request with id: {}".format(request_id)) request_data = RedisHash(request_id).to_dict() app.logger.debug("request id {} has data {}".format( request_id, request_data)) return request_data def approve_request(self, request_id): """ Deletes request and promotes request data to a public post. :param request_id: :return: JSON with result of operation """ app.logger.info("approving request with id: {}".format(request_id)) request_data = self.pop_request(request_id) result = False if request_data is not None: request_type = request_data.get("requestType") if request_type == "textpost": result = self.post.create_post(request_data) elif request_type == "listing": result = self.listing.create_listing(request_data) elif request_type == "reply": result = self.reply.create_reply(request_data) else: app.logger.error( "Unknown request type {}".format(request_type)) return jsonify({"result": result}) def deny_request(self, request_id): """ Deletes request and takes no further action :param request_id: :return: JSON with result of operation """ app.logger.info("denying request with id: {}".format(request_id)) request_data = self.pop_request(request_id) if request_data is not None and request_data.get( "requestType") == "listing": return jsonify( {"result": self.redis.remove(request_data["upload_id"])}) return jsonify({"result": False})