Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from flask import Flask, request, jsonify, request, send_from_directory
- from flask_restful import Resource, Api, abort
- from flask_httpauth import HTTPBasicAuth
- from pymongo import MongoClient
- from bson.objectid import ObjectId
- from pymongo.errors import DuplicateKeyError
- from geopy.geocoders import Nominatim
- from geopy.exc import GeocoderTimedOut
- from dateutil.parser import parse as dateparse
- from recommended_script import computeRecommended
- from nearby_script import computNearby
- from operator import itemgetter
- from datetime import datetime
- from glob import glob
- import shutil
- import os
- import imghdr
- today = datetime.utcnow()
- events = MongoClient('localhost', 27017)['app']['events']
- users = MongoClient('localhost', 27017)['app']['users']
- '''
- recommended = MongoClient('localhost', 27017)['app']['recommended']
- nearby = MongoClient('localhost', 27017)['app']['nearby']
- '''
- def joinPath(base_dir, fileDir):
- return os.path.join(base_dir, fileDir)
- def currentPath():
- return os.path.dirname(os.path.abspath(__file__))
- def parentDir(currentDir):
- return os.path.abspath(os.path.join(currentDir, os.pardir))
- upload_dir = parentDir(parentDir(currentPath()))
- if not os.path.isdir(joinPath(upload_dir, "users")):
- os.makedirs(joinPath(upload_dir, "users"))
- app = Flask(__name__, static_url_path = "", static_folder = upload_dir)
- auth = HTTPBasicAuth()
- geolocator = Nominatim()
- @auth.get_password
- def get_password(user_id):
- query = users.find({"_id": user_id})
- if query.count() == 1:
- return query[0]['password']
- return None
- class Verify(Resource):
- '''
- Essa rota deve ser chamada pelo app sempre que o usuario tocar no campo
- "Meus Eventos" e possuir conexao (obvio).
- Acionando o metodo get dessa rota,
- o servidor ira atualizar a lista de eventos passados e futuros daquele usuario
- O metodo get dessa rota tambem serve para a verificacao da existencia do usuario.
- '''
- decorators = [auth.login_required]
- def get(self, user_id):
- query = users.find({"_id": user_id})
- if query.count() == 1:
- if 'next' in query[0]:
- past_id = [i for i in query[0]['next'] if i['date'] < today]
- users.update_one({"_id": user_id}, {'$pull':{'next':{'date': {'$lt':today}}}})
- for i in past_id:
- users.update_one({"_id": user_id}, {'$push':{'past':i}})
- return {"response": True}
- return {"response": True}
- else:
- return {"response": False}
- class NewUser(Resource):
- '''
- Cadastro via e-mail: Recebe os dados usuais e uma hash de senha
- Cadastro via Facebook: Recebe os dados usuais e uma senha padrao 'Facebook'
- '''
- def post(self):
- '''
- O id do usuario sera seu email
- '''
- data = request.get_json()
- if not data:
- abort(400)
- else:
- _id = request.json.get('_id')
- f_name = request.json.get('first_name')
- l_name = request.json.get('last_name')
- password = request.json.get('password')
- preference = request.json.get('preferences')
- gender = request.json.get('gender')
- #Se algum desses campos acima for vazio, erro 400 eh acionado
- if _id is None or password is None or f_name is None or l_name is None or preference is None or gender is None:
- abort(400)
- #Se existir algum _id com o mesmo que estamos tentando inserir, retorna mensagem de erro
- if users.find({'_id':_id}).count() == 1:
- return {'response': False}
- else:
- #Se nao, adiciona o _id do usuario nas outras colecoes
- users.insert_one(data)
- user_dir = joinPath(joinPath(upload_dir,"users"),_id)
- for i in ['profile', 'events']:
- os.makedirs(joinPath(user_dir, i))
- '''
- nearby.insert_one({'_id': _id, "events_near": []})
- recommended.insert_one({'_id': _id, "similarities": []})
- '''
- return {'response': True}
- class UserLogged(Resource):
- decorators = [auth.login_required]
- def post(self, user_id):
- '''
- O metodo get dessa rota foi pensado tanto pra recuperacao de login de um usuario
- quanto pra busca de um usuario por outro
- '''
- flag = request.json.get('flag')
- if flag is None:
- abort(400)
- '''
- Recebe uma flag, pois se for o proprio usuario que requisita a consulta sobre si mesmo,
- ele retorna mais detalhes. Isso acontece na inicializacao do app para usuario ja cadastrados
- '''
- query = users.find({"_id": user_id},{'address':0, 'coordinates':0, 'password': 0})
- if query.count() == 1:
- user = query[0]
- if flag is True:
- if 'past' in user:
- user['past'] = [str(i['event_id']) for i in user['past']]
- if 'next' in user:
- user['next'] = [str(i['event_id']) for i in user['next']]
- if 'by_me' in user:
- user['by_me'] = [str(i['event_id']) for i in user['by_me']]
- else:
- user.pop("past", None)
- user.pop("next", None)
- user.pop("by_me", None)
- user.pop("preferences", None)
- return jsonify(user)
- else:
- return {"message": "no user found"}
- def put(self, user_id):
- #alterar alguma informacao dele mesmo
- data = request.get_json()
- if not data:
- abort(400)
- else:
- resp = {"response": True}
- '''
- Se o cidadao quiser atualizar as coordenadas dele, teremos que fazer a verificacao
- da existencia de um campo chamado coordinates
- '''
- if 'coordinates' in data:
- try:
- '''
- Caso tenha, teremos que recuperar um endereco pra filtragem da comparacao posteriormente
- Aqui precisa de um try/except pois as vezes da falha de timeout
- '''
- location = geolocator.reverse(tuple(data['coordinates']))
- data.update({'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}})
- except GeocoderTimedOut as e:
- resp.update({"response": False})
- if '_id' in data:
- '''
- Aqui eh para quando for a alteracao do email, como no mongo nao da pra alterar um
- _id, temos que criar um documento igual aquele cujo _id eh o anterior a alteracao
- e depois que inserir no banco esse documento e a atualizacao dele, excluimos o anteior
- '''
- user = users.find_one({"_id": user_id})
- #user["_id"] = data["_id"]
- user.update(data)
- try:
- users.insert_one(user)
- except DuplicateKeyError:
- return {"response": False}
- users.delete_one({'_id': user_id})
- return {"response": True}
- users.update_one({'_id': user_id}, {'$set': data})
- return resp
- #deletar seu perfil
- def delete(self, user_id):
- user_item = users.delete_one({'_id': user_id})
- try:
- user_dir = joinPath(joinPath(upload_dir,"users"), user_id)
- shutil.rmtree(user_dir)
- except e:
- print e
- pass
- '''
- nearby_item = nearby.delete_one({'_id': user_id})
- recommended_item = recommended.delete_one({'_id': user_id})
- '''
- if user_item.deleted_count:
- return {"response":True}
- else:
- {"response" : False}
- class UniqueEventSearch(Resource):
- decorators = [auth.login_required]
- '''
- Um usuario pode:
- '''
- def get(self, event_id):
- #Recuperar informacoes de um evento qualquer
- '''
- event_id = request.json.get('event_id')
- if event_id is None:
- abort(400)
- '''
- try:
- event_id = ObjectId(event_id)
- except:
- abort(400)
- query = events.find({"_id": event_id},{'_id':0})
- if query.count() > 0:
- n_going = len(query[0]['going'])
- query[0].update({'number_going':n_going})
- return jsonify(query[0])
- else:
- return {"message": "no event found"}
- class NearbyEventSearch(Resource):
- decorators = [auth.login_required]
- def post(self, user_id):
- data = request.get_json()
- if user_id:
- '''
- Pra calcular os eventos proximos, precisamos que o usuario tenha ativado a localizacao
- e precisamos que ele mande a pareferencia de raio de busca
- '''
- skip = request.json.get('skip')
- limit = request.json.get('limit')
- preference = request.json.get('preference')
- coordinates = request.json.get('coordinates')
- if skip is None or limit is None or coordinates is None:
- abort(400)
- try:
- location = geolocator.reverse(tuple(coordinates), timeout = 50)
- users.update_one({"_id": user_id},{"$set":{'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}}}, upsert=True)
- except GeocoderTimedOut:
- if(users.find_one({"_id": user_id, "address":{"$exists": True}})):
- pass
- else:
- return jsonify({"message":"no location found"})
- finally:
- events_nearby = computNearby(users.find_one({'_id':user_id}), events, preference, coordinates)
- events_nearby = events_nearby[skip:limit]
- for i in range(len(events_nearby)):
- event = events.find_one({'_id': events_nearby[i]['event_id']},{'address':0, "promoter":0,'contact':0, 'coordinates':0, 'preferences':0})
- event.update({"distance": events_nearby[i]["distance"]})
- events_nearby[i] = event
- [event.update({'_id':str(event['_id']), 'number_going': len(event['going'])}) for event in events_nearby]
- [event.pop("going", None) for event in events_nearby]
- return jsonify(events_nearby)
- else:
- abort(400)
- class PopularEventSearch(Resource):
- decorators = [auth.login_required]
- def post(self):
- coordinates = request.json.get('coordinates')
- skip = request.json.get('skip')
- limit = request.json.get('limit')
- if coordinates is None or skip is None or limit is None:
- abort(400)
- try:
- location = geolocator.reverse(tuple(coordinates), timeout = 50)
- users.update_one({"_id": user_id},{"$set":{'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}}}, upsert=True)
- except GeocoderTimedOut:
- if(users.find_one({"_id": user_id, "address":{"$exists": True}})):
- pass
- else:
- return jsonify({"message":"no location found"})
- finally:
- allEvents = [e for e in events.find({"address":{'state':location.raw['address']['state'], 'country':location.raw['address']['country']}, 'date':{'$gte':today}},{'address':0, "promoter":0,'contact':0, 'coordinates':0})]
- [event.update({'_id':str(event['_id']), 'number_going': len(event['going'])}) for event in allEvents]
- L = sorted(allEvents, key=itemgetter('number_going'), reverse=True)
- return jsonify(L[skip:limit])
- class MyEvents(Resource):
- decorators = [auth.login_required]
- '''
- Um usuario pode requisitar os eventos que ou ele criou, ou ele foi ou ele vai
- '''
- def post(self, user_id):
- if user_id:
- skip = request.json.get('skip')
- limit = request.json.get('limit')
- #Exige que entre um skip e um limit de range para a lista de eventos
- if skip is None or limit is None:
- abort(400)
- #Abaixo esta sendo recuperada a lista dos eventos em by_me, next e past
- byme_events_id = []
- next_events_id = []
- past_events_id = []
- by_me = users.find_one({"_id": user_id}, {"by_me": 1, "_id":0})
- if "by_me" in by_me:
- byme_events_id = by_me["by_me"]
- next = users.find_one({"_id": user_id}, {"next": 1, "_id":0})
- if "next" in next:
- next_events_id = next["next"]
- past = users.find_one({"_id": user_id}, {"past": 1, "_id":0})
- if "past" in past:
- past_events_id = past["past"]
- #A lista de meus eventos vem primeiro, seguido pelos proximos e por ultipo vem os passados
- MyEventsList_ids = byme_events_id + next_events_id + past_events_id
- MyEventsList = [events.find_one({"_id": e["event_id"]}, {'_id':0}) for e in MyEventsList_ids]
- return jsonify(MyEventsList[skip:limit])
- class RecommendedEventSearch(Resource):
- decorators = [auth.login_required]
- '''
- um usuario pode
- '''
- def post(self, user_id):
- #requisitar uma lista de eventos recomendados
- if user_id:
- skip = request.json.get('skip')
- limit = request.json.get('limit')
- coordinates = request.json.get('coordinates')
- if skip is None or limit is None or coordinates is None:
- abort(400)
- try:
- location = geolocator.reverse(tuple(coordinates), timeout = 50)
- users.update_one({"_id": user_id},{"$set":{'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}}}, upsert=True)
- except GeocoderTimedOut:
- if(users.find_one({"_id": user_id, "address":{"$exists": True}})):
- pass
- else:
- return jsonify({"message":"no location found"})
- finally:
- events_recommended = computeRecommended(users.find_one({'_id':user_id}), events)
- events_recommended = [events.find_one({'_id': d['event_id']},{'address':0, "promoter":0,'contact':0, 'coordinates':0, 'preferences':0}) for d in events_recommended[skip:limit]]
- [event.update({'_id':str(event['_id']), 'number_going': len(event['going'])}) for event in events_recommended]
- [event.pop("going", None) for event in events_recommended]
- return jsonify(events_recommended)
- else:
- abort(400)
- class Event(Resource):
- decorators = [auth.login_required]
- def post(self):
- data = request.get_json()
- if not data:
- abort(400)
- else:
- '''
- Um evento, assim como um usuario tem um campo chamado address que contem um state e um country,
- porem um evento ainda tem o campo c_address que contem o endereco inserido pelo promoter do evento,
- esse c_address eh o que aparecera no app, o address sera ignorado pelo app
- '''
- name = request.json.get('name')
- promoter = request.json.get('promoter')
- contact = request.json.get('contact')
- date = request.json.get('date')
- preferences = request.json.get('preferences')
- coordinates = request.json.get('coordinates')
- c_address = request.json.get('c_address')
- about = request.json.get('about')
- if about is None or coordinates is None or c_address is None or name is None or promoter is None or contact is None or date is None or preferences is None:
- abort(400)
- date = dateparse(date)
- event = events.find({"name": name, "promoter":promoter, "contact":contact, 'date':date, 'coordinates':coordinates})
- if event.count() == 0:
- try:
- '''
- Caso tenha, teremos que recuperar um endereco pra filtragem da comparacao posteriormente
- Aqui precisa de um try/except pois as vezes da falha de timeout
- '''
- location = geolocator.reverse(tuple(coordinates))
- data.update({'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}})
- except GeocoderTimedOut as e:
- return {'message': "location not found"}
- data.update({'date':date, 'going':[]})
- event_id = events.insert_one(data)
- user = users.update_one({"_id": promoter}, {"$push":{"by_me": {"event_id": event_id.inserted_id, "date" : date}}})
- user_dir = joinPath(joinPath(upload_dir,"users"), promoter)
- event_dir = joinPath(user_dir, "events")
- os.makedirs(joinPath(event_dir, str(event_id.inserted_id)))
- return {'message' : str(event_id.inserted_id)}
- else:
- return {'response' : False}
- def put(self):
- #alterar uma informacao do evento
- data = request.get_json()
- if not data:
- abort(400)
- else:
- event_id = request.json.get('event_id')
- date = request.json.get('date')
- coordinates = request.json.get('coordinates')
- if event_id is None:
- abort(400)
- if date is not None:
- date = dateparse(date)
- data.update({'date':date})
- if coordinates is not None:
- try:
- '''
- Caso tenha, teremos que recuperar um endereco pra filtragem da comparacao posteriormente
- Aqui precisa de um try/except pois as vezes da falha de timeout
- '''
- location = geolocator.reverse(tuple(coordinates))
- data.update({'address':{'state': location.raw['address']['state'], 'country':location.raw['address']['country']}})
- except GeocoderTimedOut as e:
- return {'response':False}
- #event = events.find({"name": name, "promoter":promoter, "contact":contact, 'date':date, 'coordinates':coordinates})
- try:
- event_id = ObjectId(event_id)
- except:
- abort(400)
- data.pop("_id",None)
- events.update_one({"_id": event_id}, {'$set': data})
- return {'response': True}
- class DeleteEvent(Resource):
- decorators = [auth.login_required]
- def delete(self, event_id):
- #deletar um evento
- '''
- event_id = request.json.get('event_id')
- if event_id is None:
- abort(400)
- '''
- try:
- event_id = ObjectId(event_id)
- except:
- abort(400)
- promoter = events.find_one({"_id": event_id})["promoter"]
- event_item = events.delete_one({"_id":event_id})
- users.update_many({}, {'$pull':{'past':{'event_id': event_id}}})
- users.update_many({}, {'$pull':{'next':{'event_id': event_id}}})
- users.update({}, {'$pull':{'by_me':{'event_id': event_id}}})
- user_dir = joinPath(joinPath(upload_dir,"users"), promoter)
- event_dir = joinPath(user_dir, "events")
- if os.path.isdir(joinPath(event_dir, str(event_id))):
- shutil.rmtree(joinPath(event_dir, str(event_id)))
- '''
- nearby.update_many({},{'$pull':{'events_near':{'event_id': event_id}}})
- recommended.update_many({}, {'$pull':{'similarities':{'event_id': event_id}}})
- '''
- if event_item.deleted_count:
- return {"response":True}
- else:
- {"response" : False}
- class Going(Resource):
- decorators = [auth.login_required]
- '''
- Para participar (post) e deixar de participar (delete) de um evento
- '''
- def post(self, user_id, event_id):
- '''
- user_id = request.json.get('_id')
- if user_id is None:
- abort(400)
- '''
- try:
- event_id = ObjectId(event_id)
- ObjectId(event_id)
- except:
- abort(400)
- else:
- event = events.find_one({"_id":event_id, 'date':{'$gte':today}})
- if event:
- events.update_one({"_id":event_id},{'$push':{'going':user_id}})
- users.update_one({"_id":user_id}, {'$push':{'next':{"event_id": event_id, "date" : event['date']}}})
- return {'response': True}
- else:
- return {'response': False}
- def delete(self, user_id, event_id):
- '''
- user_id = request.json.get('_id')
- if user_id is None:
- abort(400)
- '''
- try:
- event_id = ObjectId(event_id)
- ObjectId(event_id)
- except:
- abort(400)
- else:
- events.update_one({"_id":event_id},{'$pull':{'going':user_id}})
- users.update_one({"_id":user_id}, {'$pull':{'next':{"event_id": event_id}}})
- return {'response': True}
- class UserPhoto(Resource):
- decorators = [auth.login_required]
- def get(self,user_id):
- '''
- fazendo GET atraves do requests:
- from PIL import Image
- from StringIO import StringIO
- r = requests.get('http://localhost:80/users/user_id')
- i = Image.open(StringIO(r.content))
- i.save("arquivo.jpeg")
- '''
- photoDir = joinPath(upload_dir, joinPath(joinPath("users",user_id), "profile"))
- try:
- #ext = imghdr.what(glob(joinPath(photoDir,"*.*"))[0])
- #if ext in ['jpeg', 'jpg', 'png']:
- image = send_from_directory(photoDir,"profile_photo_"+ user_id+".jpg")
- except Exception as e:
- print e
- return {"response": False}
- else:
- return image
- def post(self, user_id):
- if 'file' in request.files:
- file = request.files['file']
- if file:
- try:
- photoDir = joinPath(upload_dir, joinPath(joinPath("users",user_id), "profile"))
- file.save(joinPath(photoDir,"profile_photo_"+user_id+".jpg"))
- except Exception as e:
- print e
- return {"response": False}
- else:
- return {"response": True}
- else:
- print 1
- abort(400)
- else:
- print 2
- abort(400)
- class EventPhoto(Resource):
- decorators = [auth.login_required]
- def get(self, user_id, event_id):
- eventsDir = joinPath(upload_dir, joinPath(joinPath("users",user_id), "events"))
- photoDir = joinPath(eventsDir,event_id)
- try:
- #ext = imghdr.what(glob(joinPath(photoDir,"*.*"))[0])
- #if ext in ['jpeg', 'jpg', 'png']:
- image = send_from_directory(photoDir,"event_photo_"+ event_id+".jpeg")
- except Exception as e:
- print e
- return {"response": False}
- else:
- return image
- def post(self, user_id, event_id):
- if 'file' in request.files:
- file = request.files['file']
- if file:
- try:
- eventDir = joinPath(upload_dir, joinPath(joinPath("users",user_id), "events"))
- photoDir = joinPath(eventDir,event_id)
- file.save(joinPath(photoDir,"event_photo_"+event_id+".jpg"))
- except Exception as e:
- #print e
- return {"response": False}
- else:
- return {"response": True}
- else:
- abort(400)
- else:
- abort(400)
- api = Api(app)
- api.add_resource(Verify, "/verify/<string:user_id>")
- api.add_resource(NewUser, "/new_user")
- api.add_resource(UserLogged, "/user/<string:user_id>")
- api.add_resource(UniqueEventSearch, "/unique_event_search/<string:event_id>")
- api.add_resource(NearbyEventSearch, "/nearby_event_search/<string:user_id>")
- api.add_resource(RecommendedEventSearch, "/recommended_event_search/<string:user_id>")
- api.add_resource(PopularEventSearch, "/popular_event_search")
- api.add_resource(Event, "/events")
- api.add_resource(DeleteEvent, "/events/<string:event_id>")
- api.add_resource(MyEvents, "/myevents/<string:user_id>")
- api.add_resource(Going, "/go/<string:user_id>/<string:event_id>")
- api.add_resource(UserPhoto, "/upload/<string:user_id>")
- api.add_resource(EventPhoto, "/upload/<string:user_id>/<string:event_id>")
- if __name__ == '__main__':
- app.run(host='0.0.0.0', port=80)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement