def errors(self): errors = ApiErrors() data = self.__class__.__table__.columns._data for key in data.keys(): col = data[key] val = getattr(self, key) if not isinstance(col, Column): continue if not col.nullable\ and not col.foreign_keys\ and not col.primary_key\ and col.default is None\ and val is None: errors.addError(key, 'Cette information est obligatoire') if val is None: continue if (isinstance(col.type, String) or isinstance(col.type, CHAR))\ and not isinstance(col.type, Enum)\ and not isinstance(val, str): errors.addError(key, 'doit etre une chaine de caracteres') if (isinstance(col.type, String) or isinstance(col.type, CHAR))\ and isinstance(val, str)\ and col.type.length\ and len(val)>col.type.length: errors.addError( key, 'Vous devez saisir moins de ' + str(col.type.length) + ' caracteres') if isinstance(col.type, Integer)\ and not isinstance(val, int): errors.addError(key, 'doit etre un entier') if isinstance(col.type, Float)\ and not isinstance(val, float): errors.addError(key, 'doit etre un nombre') return errors
def export_table(model_name): check_token() ae = ApiErrors() try: model = app.model[model_name] except KeyError: ae.addError('global', 'Nom de classe incorrect : '+model_name) return jsonify(ae.errors), 400 if not is_exportable(model_name): ae.addError('global', 'Classe non exportable : '+model_name) return jsonify(ae.errors), 400 objects = model.query.all() csvfile = StringIO() header = objects[0]._asdict().keys() if model_name == 'User': header = list(filter(lambda h: h!='id' and h!='password', header)) writer = csv.DictWriter(csvfile, header) writer.writeheader() for obj in objects: dct = obj._asdict() if model_name == 'User': del(dct['password']) del(dct['id']) writer.writerow(dct) csvfile.seek(0) mem = BytesIO() mem.write(csvfile.getvalue().encode('utf-8')) mem.seek(0) csvfile.close() return send_file(mem, attachment_filename='export.csv', as_attachment=True)
def get_offerer(id): dehumanize_id = dehumanize(id) for offerer in current_user.offerers: if offerer.id == dehumanize_id: return jsonify(offerer._asdict(include=OFFERERS_INCLUDES)), 200 e = ApiErrors() e.addError('global', "Cette structure n'est pas enregistrée chez cet utilisateur.") return jsonify(e.errors), 400
def check_token(): if EXPORT_TOKEN is None or EXPORT_TOKEN == '': raise ValueError("Missing environment variable EXPORT_TOKEN") token = request.args.get('token') ae = ApiErrors() if token is None: ae.addError('token', 'Vous devez préciser un jeton dans l''adresse (token=XXX)') if not token == EXPORT_TOKEN: ae.addError('token', 'Le jeton est invalide') if ae.errors: raise ae
def list_offerers_venues(id): dehumanize_id = dehumanize(id) for offerer in current_user.offerers: if offerer.id == dehumanize_id: venues = [ o._asdict(include=VENUES_INCLUDES) for o in offerer.managedVenues ] return jsonify(venues), 200 e = ApiErrors() e.addError('global', "Cette structure n'est pas enregistrée chez cet utilisateur.") return jsonify(e.errors), 400
def list_venue_providers(): venueId = request.args.get('venueId') if venueId is None: e = ApiErrors() e.addError('venueId', 'Vous devez obligatoirement fournir le paramètre venueId') return jsonify(e.errors), 400 vp_query = VenueProvider.query\ .filter_by(venueId=dehumanize(venueId)) return jsonify([ vp._asdict(include=VENUE_PROVIDER_INCLUDES) for vp in vp_query.all() ])
def check_and_save(*objects): if not objects: raise ValueError('Objects to save need to be passed as arguments' + ' to check_and_save') # CUMULATE ERRORS IN ONE SINGLE API ERRORS DURING ADD TIME api_errors = ApiErrors() for obj in objects: obj_api_errors = obj.errors() if obj_api_errors.errors.keys(): api_errors.errors.update(obj_api_errors.errors) else: db.session.add(obj) # CHECK BEFORE COMMIT if api_errors.errors.keys(): raise api_errors # COMMIT try: db.session.commit() except DataError as de: api_errors.addError(*BaseObject.restize_data_error(de)) raise api_errors except IntegrityError as ie: api_errors.addError(*BaseObject.restize_integrity_error(ie)) raise api_errors except TypeError as te: api_errors.addError(*BaseObject.restize_type_error(te)) raise api_errors except ValueError as ve: api_errors.addError(*BaseObject.restize_value_error(ve)) raise api_errors if api_errors.errors.keys(): raise api_errors
def post_booking(): offer_id = request.json.get('offerId') ae = ApiErrors() if current_user.canBook == False: ae.addError('canBook', 'L\'utilisateur n\'a pas le droit de réserver d\'offre') return jsonify(ae.errors), 400 if offer_id is None: ae.addError('offerId', 'Vous devez préciser un identifiant d\'offre') return jsonify(ae.errors), 400 offer = Offer.query.filter_by(id=dehumanize(offer_id)).first() if offer is None: ae.addError('offerId', 'offerId ne correspond à aucune offer') return jsonify(ae.errors), 400 if offer.bookingLimitDatetime is not None and\ offer.bookingLimitDatetime < datetime.utcnow(): ae.addError( 'global', 'la date limite de réservation de cette offre' + ' est dépassée') return jsonify(ae.errors), 400 new_booking = Booking() new_booking.offerId = dehumanize(offer_id) token = random_token() new_booking.token = token new_booking.user = current_user recommendation_id = request.json.get('recommendationId') if recommendation_id is not None: new_booking.recommendationId = dehumanize(recommendation_id) try: app.model.PcObject.check_and_save(new_booking) except InternalError as ie: if 'check_booking' in str(ie.orig): ae.addError( 'global', 'la quantité disponible pour cette offre' + ' est atteinte') return jsonify(ae.errors), 400 else: raise ie send_booking_recap_emails(app.model.Offer.query.get(new_booking.offerId), new_booking) return jsonify(new_booking._asdict(include=BOOKINGS_INCLUDES, venueTz=True)), 201
def handle_rest_get_list(modelClass, query=None, filter_fn=None, refine=None, order_by=None, flask_request=None, include=None, resolve=None, print_elements=None, paginate=None, page=None): if flask_request is None: flask_request = request if query is None: query = modelClass.query # DELETED if hasattr(modelClass, 'deleted'): query = query.filter_by(deleted=False) # FILTER filters = flask_request.args.copy() if filter_fn: query = filter_fn(query, filters) # REFINE if refine: query = refine(query) # ORDER BY if order_by: try: order_by = [order_by] if not isinstance(order_by, list)\ else order_by query = query.order_by(*order_by) except ProgrammingError as e: field = re.search('column "?(.*?)"? does not exist', e._message, re.IGNORECASE) if field: errors = ApiErrors() errors.addError('order_by', 'order_by value references an unknown field : '+field.group(1)) raise errors else: raise e # PAGINATE if paginate: page = 'page' in filters and filters['page'] query = query.paginate(page, per_page=paginate, error_out=False)\ .items # DICTIFY elements = list(map( lambda o: o._asdict( include=include, resolve=resolve, filters=filters ), query)) # PRINT if print_elements: print(elements) # RETURN return jsonify(elements), 200
def edit_offer(offer_id): updated_offer_dict = request.json query = Offer.query.filter_by(id=dehumanize(offer_id)) offer = query.first_or_404() ensure_provider_can_update(offer) update(offer, updated_offer_dict) try: app.model.PcObject.check_and_save(offer) except InternalError as ie: if 'check_offer' in str(ie.orig): ae = ApiErrors() ae.addError( 'available', 'la quantité pour cette offre' + ' ne peut pas être inférieure' + ' au nombre de réservations existantes.') return jsonify(ae.errors), 400 else: raise ie return jsonify(offer._asdict(include=OFFERS_INCLUDES)), 200
def create_mediation(): # TODO: Allow to receive a URL from request.form['thumb'] # save_thumb already does it so it should be easy, but I can't make it ... if 'thumb' not in request.files\ or request.files['thumb'].filename == '': e = ApiErrors() e.addError('thumb', "Vous devez fournir une image d'accroche") return jsonify(e.errors), 400 thumb = request.files['thumb'] filename_parts = thumb.filename.rsplit('.', 1) if len(filename_parts)<2\ or filename_parts[1].lower() not in ALLOWED_EXTENSIONS: e = ApiErrors() e.addError('thumb', "Ce format d'image n'est pas autorisé") return jsonify(e.errors), 400 offererId = dehumanize(request.form['offererId']) ensure_current_user_has_rights(RightsType.editor, offererId) new_mediation = Mediation() new_mediation.author = current_user new_mediation.eventId = dehumanize(request.form['eventId']) new_mediation.offererId = offererId app.model.PcObject.check_and_save(new_mediation) if 'croppingRect[x]' in request.form: crop = [ float(request.form['croppingRect[x]']), float(request.form['croppingRect[y]']), float(request.form['croppingRect[height]']) ] else: crop = None new_mediation.save_thumb(thumb.read(), 0, crop=crop) return jsonify(new_mediation), 201
def find_or_make_recommendation(user, occasion_type, occasion_id, mediation_id, from_user_id=None): query = Recommendation.query print('(special) offer_id', occasion_id, 'mediation_id', mediation_id) if not mediation_id and not (occasion_id and occasion_type): return None if mediation_id: filter = (Recommendation.mediationId == mediation_id) elif occasion_id and occasion_type: if occasion_type == 'thing': filter = (Recommendation.thingId == mediation_id) elif occasion_type == 'event': filter = (Recommendation.eventId == mediation_id) else: ae = ApiErrors() ae.addError('occasion_type', "Invalid occasion type : " + occasion_type) raise ae requested_recommendation = query.filter(filter & (Recommendation.userId==user.id))\ .first() if requested_recommendation is None: if mediation_id: return None elif occasion_type == 'thing': occasion = Thing.query.get(occasion_id) elif occasion_type == 'event': occasion = Event.query.get(occasion_id) mediation = Mediation.query.get(mediation_id) requested_recommendation = create_recommendation(user, occasion, mediation=mediation) return requested_recommendation
def get_user_with_credentials(identifier, password): errors = ApiErrors() errors.status_code = 401 if identifier is None: errors.addError('identifier', 'Identifiant manquant') if password is None: errors.addError('password', 'Mot de passe manquant') errors.maybeRaise() user = User.query.filter_by(email=identifier).first() if not user: errors.addError('identifier', 'Identifiant incorrect') raise errors if not user.checkPassword(password): errors.addError('password', 'Mot de passe incorrect') raise errors login_user(user, remember=True) return user
def send_401(): e = ApiErrors() e.addError('global', 'Authentification nécessaire') return jsonify(e.errors), 401
def signup(): if 'contact_ok' not in request.json or\ (request.json['contact_ok'] is not True and str(request.json['contact_ok']).lower() != 'true'): e = ApiErrors() e.addError('contact_ok', 'Vous devez obligatoirement cocher cette case') return jsonify(e.errors), 400 departement_code = None if 'email' in request.json: scope = [ 'https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive' ] key_path = Path(path.dirname( path.realpath(__file__))) / '..' / 'private' / 'google_key.json' credentials = ServiceAccountCredentials.from_json_keyfile_name( key_path, scope) gc = gspread.authorize(credentials) spreadsheet = gc.open_by_key( '1YCLVZNU5Gzb2P4Jaf9OW50Oedm2-Z9S099FGitFG64s') worksheet = spreadsheet.worksheet('Utilisateurs') labels = worksheet.row_values(1) email_index = None departement_index = None for index, label in enumerate(labels): if label == 'Email': email_index = index elif label == 'Département': departement_index = index if email_index is None: raise ValueError("Can't find 'Email' column in users spreadsheet") if departement_index is None: raise ValueError( "Can't find 'Département' column in users spreadsheet") values = worksheet.get_all_values()[1:] authorized_emails = list(map(lambda v: v[email_index], values)) try: email_index = authorized_emails.index(request.json['email']) except ValueError: e = ApiErrors() e.addError('email', "Adresse non autorisée pour l'expérimentation") return jsonify(e.errors), 400 departement_code = values[email_index][departement_index] if departement_code.strip() == '': print( "[ERROR] Missing departement code in users spreadsheet for " + request.json['email']) e = ApiErrors() e.addError('email', "Adresse non autorisée pour l'expérimentation") return jsonify(e.errors), 400 new_user = app.model.User(from_dict=request.json) new_user.id = None new_user.departementCode = departement_code offerer = None user_offerer = None if 'siren' in request.json: #TODO: handle case of already existing Offerer new_user.canBook = False offerer = app.model.Offerer() update(offerer, request.json) user_offerer = offerer.make_admin(new_user) offerer.bookingEmail = new_user.email offerer.isActive = False app.model.PcObject.check_and_save(new_user, offerer, user_offerer) else: app.model.PcObject.check_and_save(new_user) login_user(new_user) return jsonify(new_user._asdict(include=USERS_INCLUDES)), 201