def login(self): body = request.json if body['password'] != body['confirmpassword']: raise BussinessException("error",400,"confirm password mismatch") db = self.getConnection() payload = {} result = db.user.find_one({'email':body['email'],'password':body['password']},{'_id':True,'isAdmin':True, 'firstName': True, 'lastName': True}) if not result: raise BussinessException("error",400,"Check your username and passsword!") payload['id'] = str(result['_id']) payload['firstName'] = result['firstName'] payload['firstName'] = result['lastName'] if result.get('isAdmin',None): payload['role'] = 'admin' else: payload['role'] = 'user' timestamp = self._current_timestamp() payload = { "iss": JWT_ISSUER, "iat": int(timestamp), "exp": int(timestamp + JWT_LIFETIME_SECONDS), "sub": json.dumps(payload), } # token must contain role and id of the user under sub key return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
def deleteStaticUsingUnique(self,unique): resource = self.__static_collection if not unique: raise BussinessException("error",400, "Invalid file name") result = self.db[resource].delete_one({"unique": unique}) if not result.deleted_count: raise BussinessException("error",400, "File not found") return {"file": unique, "detail": "File successfully removed"}, 200
def deleteStatic(self,type,id): resource = self.__static_collection obj_id = convertToObjectId(id) if not obj_id: raise BussinessException("error",400, "Invalid file url") result = self.db[resource].delete_one({"_id": obj_id}) if not result.deleted_count: raise BussinessException("error",400, "File not found") return {"url": type+"/"+id, "detail": "File successfully removed"}, 200
def checkStaticAuthz(self, request, token): if self.__static_rules == None: raise BussinessException("error", 500, "No rules defined; Contact Admin") # the static rest api must be static/{type}/{id} auth_type = request.view_args.get("type", None) obj_id = request.view_args.get("id", None) if auth_type is None or obj_id is None: raise BussinessException("error", 500, "Authz error; Contact Admin") subject = json.loads(token['sub']) role = subject['role'] user_id = subject['id'] if role in self.__roles_global: return True required_type = self.__static_rules.get(auth_type, None) if not required_type: return True # if url don't exist, return true authz_list = required_type.get(request.method, None) if authz_list == None: return True # if method don't exist, return true for authz in authz_list: if authz == "all": return True elif authz.find(":") == -1: if role == authz: return True else: # check for curr attr values = authz.split(":") if values[1] == "curr": obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error", 400, "Invalid File id") result = self.db[self.__static_collection].find_one( {"_id": obj_id}, { "_id": False, "owner": True }) if not result: raise BussinessException("error", 400, "File not found") if user_id == result["owner"] and values[0] == role: return True else: # check at application start and do sys.exit raise BussinessException("error", 500, "Authz error; Contact Admin") return False
def retrieve(self, obj_id, resource = None, projection = None): resource = resource if resource else self.resource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") result = self.db[resource].find_one({"_id": obj_id}, mask) if not result: raise BussinessException("error",400,resource + " not found") return result, 200
def remove(self, obj_id, resource = None, projection = None): resource = resource if resource else self.resource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400, "Invalid " + resource + " id") result = self.db[resource].delete_one({"_id": obj_id}) if not result.deleted_count: raise BussinessException("error",400,resource + " not found") return {"id": obj_id, "detail": resource + " successfully removed"}, 200
def update(self, obj_id, data, resource = None, projection = None): resource = resource if resource else self.resource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") result = self.db[resource].update_one({"_id": obj_id}, {'$set': data}) if not result.matched_count: raise BussinessException("error",400,resource + " not found") return self.db[resource].find_one({"_id": obj_id}, mask), 200
def remove_subdocument(self, obj_id, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection,subresource) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400, "Invalid " + resource + " id") result = self.db[resource].update_one({"_id": obj_id}, {'$unset': { subresource : ""}}) if not result.matched_count: raise BussinessException("error",400,subresource + " not found") return {"id": obj_id, "detail": subresource + " successfully removed"}, 200
def retriveStatic(self,type,id): resource = self.__static_collection obj_id = convertToObjectId(id) if not obj_id: raise BussinessException("error",400, "Invalid file url") result = self.db[resource].find_one({"_id": obj_id},{"_id": False,"binary": True}) if not result: raise BussinessException("error",400, "File not found") response = send_file(io.BytesIO(result['binary']), attachment_filename="download.pdf", as_attachment=True) response.headers["Content-Type"] = 'application/pdf' response.direct_passthrough = False return response, 200
def insert_array(self, obj_id, data, resource = None, subresource = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") data = { subresource : data } result = self.db[resource].update_one({"_id": obj_id}, {'$push': data}) if not result.matched_count: raise BussinessException("error",400,subresource + " not found") return self.db[resource].find_one({"_id": obj_id})[subresource], 200
def retrieve_array(self, obj_id, resource = None, subresource = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") result = self.db[resource].find_one({"_id": obj_id}) if not result: raise BussinessException("error",400,resource + " list is empty") result = result.get(subresource,None) if not result: raise BussinessException("error",400,resource + " not found") return result, 200
def checkAuthz(self, request, token): #check if the url is static if str(request.url_rule) == "/static/<type>/<id>": return self.checkStaticAuthz(request, token) if self.__rules == None: raise BussinessException("error", 500, "No rules defined; Contact Admin") subject = json.loads(token['sub']) role = subject['role'] id = subject['id'] if role in self.__roles_global: return True rule = self.__rules.get(str(request.url_rule), None) if not rule: raise BussinessException("error", 500, "Authz error; Contact Admin") authz_list = rule.get(request.method, None) if authz_list == None: raise BussinessException("error", 500, "Authz error; Contact Admin") for authz in authz_list: if authz == "all": return True elif authz.find(":") == -1: if role == authz: return True else: # check for curr attr values = authz.split(":") if values[1] == "curr": # get first path param name url_rule = str(request.url_rule) start = url_rule.find("<") end = url_rule.find(">") if start == -1 and end == -1: raise BussinessException("error", 500, "Authz error; Contact Admin") first_param = url_rule[start + 1:end] first_param_value = request.view_args.get( first_param, None) if id == first_param_value and values[0] == role: return True else: # check at application start and do sys.exit raise BussinessException("error", 500, "Authz error; Contact Admin") return False
def retrieveAll_subdocument_array(self, obj_id, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") result = self.db[resource].find_one({"_id": obj_id}, mask) if not result: raise BussinessException("error",400,resource + " list is empty") result = result.get(subresource,None) if not result: raise BussinessException("error",400,resource + " not found") return result, 200
def insert_subdocument_array(self, obj_id, data, resource = None, subresource = None, projection = None, objectId = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") sub_obj_id = data["_id"] = objectId if objectId else ObjectId() # sub_obj_id data = { subresource : data } result = self.db[resource].update_one({"_id": obj_id}, {'$push': data}) if not result.matched_count: raise BussinessException("error",400,subresource + " not found") return self.db[resource].find_one({ subresource+"._id" : sub_obj_id }, {subresource + ".$" : 1}).get(subresource)[0]
def remove_subdocument_array(self, obj_id, sub_obj_id, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") sub_obj_id = convertToObjectId(sub_obj_id) if not sub_obj_id: raise BussinessException("error",400,resource + "Invalid " + subresource + " id") result = self.db[resource].find_one({ subresource+"._id" : sub_obj_id }, {subresource + ".$" : 1}) if not result: raise BussinessException("error",400,resource + subresource + " not found") result = self.db[resource].update_one({ "_id": obj_id}, {'$pull': {subresource : {"_id" : sub_obj_id }}}) # since we find with obj_id, it always matches and result.matchcount will be 1 return {"id": sub_obj_id, "detail": subresource + " successfully removed"}, 200
def retrieveAll(self, search=None, resource = None, projection = None): resource = resource if resource else self.resource mask = self.projection_helper(projection) if projection else self.mask result = list(self.db[resource].find(search, mask)) if not result: raise BussinessException("error",400,resource + " list is empty") return result, 200
def update_subdocument(self, obj_id, data, unset_data = None, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection,subresource) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") # optimse this using only data and removing unset_data update = {} if data: update['$set'] = self.subresource_update_data_helper(data, subresource) if unset_data: update['$unset'] = self.subresource_update_data_helper(unset_data, subresource) result = self.db[resource].update_one({"_id": obj_id}, update) if not result.matched_count: raise BussinessException("error",400,resource + " not found") return self.db[resource].find_one({"_id": obj_id}, mask)[subresource], 200
def remove_array(self, obj_id, value, resource = None, subresource = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,"Invalid " + resource + " id") print(value) self.db[resource].update_one({ "_id": obj_id}, {'$pull': {subresource : { '$in': [value] }}}) return self.db[resource].find_one({"_id": obj_id})[subresource], 200
def insert(self, data, resource = None, projection = None, objectId = None): resource = resource if resource else self.resource mask = self.projection_helper(projection) if projection else self.mask if objectId: data["_id"] = objectId try: obj_id = self.db[resource].insert_one(data).inserted_id except errors.DuplicateKeyError: raise BussinessException("error",400,resource + " already exists") return self.db[resource].find_one({"_id": obj_id}, mask), 200
def update_subdocument_array(self, obj_id, data, sub_obj_id, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400, "Invalid " + resource + " id") sub_obj_id = convertToObjectId(sub_obj_id) if not sub_obj_id: raise BussinessException("error",400,resource + subresource + " id") data = self.subresource_array_update_data_helper(data,subresource) result = self.db[resource].update_one({ subresource+"._id" : sub_obj_id}, {'$set': data }) if not result.matched_count: raise BussinessException("error",400,subresource + " not found") result = self.db[resource].find_one({ subresource+"._id" : sub_obj_id}, mask) result = result.get(subresource,None)[0] if not result: raise BussinessException("error",400,resource + subresource + " not found") return result, 200
def decode_token(token): try: decoded_token = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) authz = Authz.getInstance() allow = authz.checkAuthz(request,decoded_token) if not allow: raise BussinessException("Forbidden",403,"No permission") return decoded_token except JWTError as e: six.raise_from(Unauthorized, e)
def retrieve_subdocument_array(self, obj_id, sub_obj_id, resource = None, subresource = None, projection = None): resource = resource if resource else self.resource subresource = subresource if subresource else self.subresource mask = self.projection_helper(projection) if projection else self.mask obj_id = convertToObjectId(obj_id) if not obj_id: raise BussinessException("error",400,resource + "Invalid " + resource + " id") sub_obj_id = convertToObjectId(sub_obj_id) if not sub_obj_id: raise BussinessException("error",400,resource + "Invalid " + subresource + " id") print(subresource) result = self.db[resource].find_one({ subresource+"._id" : sub_obj_id }, {subresource + ".$" : 1}) # Using non-Index field to query. Use aggregate to improve performace. # query with parent index and then with sub index if not result: raise BussinessException("error",400,resource + " not found") result = result.get(subresource,None)[0] if not result: raise BussinessException("error",400,resource + " not found") return result, 200
def uploadStatic(self,file,meta,owner,doc_prefix,unique,max): if file is None: raise BussinessException("error",400, "No file attached.") if owner is None: raise BussinessException("error",500,"Authz error; Contact Admin") if doc_prefix is None: raise BussinessException("error",500,"Authz error; Contact Admin") resource = self.__static_collection data = {} if file.filename == '': raise BussinessException("error",400, "No file selected") if not self.allowed_file(file.filename): raise BussinessException("error",400, "File format not allowed") # filenames can be dangerous, so use secure_filename meta['filename'] = secure_filename(file.filename) data['binary'] = file.read() data['meta'] = meta data['owner'] = owner if unique: data['unique'] = unique try: # replace_one doc - https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.replace_one result = self.db[resource].replace_one({"unique": unique},data, True) if result.matched_count > 1: pass # TODO log this part; dont throw error. except: raise BussinessException("error",500, "Upload document failed") obj_id = self.db[resource].find_one({"unique": unique}, {"_id": True})["_id"] else: obj_id = self.db[resource].insert_one(data,{"_id": True}).inserted_id return "/"+doc_prefix+"/"+str(obj_id)