Module collectives.utils
Contents
Module collectives.utils
#
Module collectives.utils.access
#
Decorators to help manage page access.
Knowledge of python decorator is usefull to understand this module. The documentation will not cover this subject, however, there is a lot of information about decorator on Internet.
See functools
- collectives.utils.access.access_requires(function, test, api=False)#
Decorator to do a test before granting access
It is a very generic decorator meant to have a way to create any test to grant access to an endpoint
- Parameters
f (function) – The function of the endpoint that will be protected
api (bool) – If True and access is denied, trigger a 403. Otherwise return an error message
test (function) – A function the must return a boolean. If false, access to f will be refused
- Returns
the protected (decorated) f function
- Return type
function
- collectives.utils.access.confidentiality_agreement(api=False)#
Decorator which check if user has signed confidentiality agreement.
If in api mode, a failure will returns a 403 HTTP code. Else, it will redirect with a error flash message.
- Parameters
api (function) – API mode
- Returns
the protected (decorated) f function
- Return type
function
- collectives.utils.access.payments_enabled(api=False)#
Decorator which checks whether the payment functionnality is enabled
- Parameters
api (bool) – If True and access is denied, trigger a 403. Otherwise return an error message
- Returns
the protected (decorated) f function
- Return type
function
- collectives.utils.access.technician_required_f()#
Function to limit access to technician only.
- collectives.utils.access.user_is(methods, api=False, **kwargs)#
Decorator which check if an user method to authorize access.
Example:
@user_is('is_admin') @blueprint.route("/", methods=["GET", "POST"]) def administration(): pass
- Parameters
api (bool) – If True and access is denied, trigger a 403. Otherwise return an error message
methods (list or string) – the user methods to call. WARNING: this parameter should always be a constant (no user generated data). Can be a list, in which case, user is authorized if method returns True (ie if user has at least one of the listed roles)
- Returns
the protected (decorated) f function
- Return type
function
- collectives.utils.access.valid_user(api=False)#
Decorator which check if user is logged in and has signed current legal text.
- Parameters
api (bool) – If True and access is denied, trigger a 403. Otherwise return an error message
- Returns
the protected (decorated) f function
- Return type
function
Module collectives.utils.csv
#
Module to handle csv import
- collectives.utils.csv.csv_to_events(stream, description)#
Decode the csv stream to populate events.
- Parameters
stream (
io.StringIO
) – the csv file as a stream.description (String) – Description template that will be used to generate new events description.
- Returns
The new events, the number of processed events, and the number of failed attempts
- Return type
list(
collectives.models.event.Event
), int, int
- collectives.utils.csv.fill_from_csv(event, row, template)#
Fill an Event object attributes with parameter from a csv row.
- Parameters
event (
collectives.models.event.Event
) – The evet object to populate.row (list(string)) – List of value from a csv file row
template (string) – Template for the event description. It can contains placeholders.
- Returns
Nothing
- collectives.utils.csv.parse(row, column_name)#
Parse a column value in csv format to an object depending on column type. Raise an exception if field is mandatory and is not set
- Parameters
row (list(string)) – List of value from a csv file row
column_name (string) – Column name
- Returns
The parsed value
- collectives.utils.csv.process_stream(base_stream, activity_type, description)#
Creates the events from a csv file.
Processing will first try to process it as an UTF8 encoded file. If it fails on a decoding error, it will try as Windows encoding (iso-8859-1).
- Parameters
base_stream (
io.StringIO
) – the csv file as a stream.activity_type (
collectives.models.activity_type.ActivityType
) – The type of activity of the new events.description (String) – Description template that will be used to generate new events description.
- Returns
The number of processed events, and the number of failed attempts
- Return type
(int, int)
Module collectives.utils.error
#
Module to handle HTTP errors
- collectives.utils.error.not_found(ex)#
If URL is unknown, redirect client or/and display an error message.
- Parameters
e – exception which generated the error page
- Returns
a redirection to index page
- collectives.utils.error.server_error(ex)#
Return a very simple error page.
Note: in collectives, this function is only active in non debug mode.
- Parameters
e – exception which generated the error page
- Returns
error.html page
with a 500 error code
Module collectives.utils.extranet
#
Module to handle connexions to FFCAM extranet.
- class collectives.utils.extranet.ExtranetApi#
SOAP Client to retrieve information from FFCAM servers.
- property auth_info: Dict#
Builds authorization info from config
- check_license(license_number: str) collectives.utils.extranet.LicenseInfo #
Get information on a license from FFCAM server.
- Parameters
license_number (string) – License to get information about.
- disabled() bool #
Check if soap client has been initialized.
If soap client has not been initialized, it means we are in dev mode.
- Returns
True if ExtranetApi is disabled.
- fetch_user_info(license_number: str) collectives.utils.extranet.UserInfo #
Get user information on a license from FFCAM server.
- Parameters
license_number – User license to get information about.
- Returns
Licence information, or None in case of API error
- init_app(app: flask.app.Flask)#
Initializes the API for the given Flask app
- property soap_client: zeep.proxy.ServiceProxy#
Returns the cached SOAP client or initialize a new one
- exception collectives.utils.extranet.ExtranetError#
An exception indicating that something has gone wrong with extranet API
- exception collectives.utils.extranet.LicenseBelongsToOtherClubError#
An exception indicating that the tested license belongs to another club
- class collectives.utils.extranet.LicenseInfo#
Licence information as retrieved from FFCAM servers.
- exists: bool#
If licence exists.
- expiry_date() datetime.date #
Get licence expiration date.
Licence expire at the start of the month LICENSE_EXPIRY_MONTH which follow the renewal date.
- Returns
License expiration date. None if renewal_date is None
- is_valid_at_time(time: datetime.datetime) bool #
Check if license is valid at a given date.
- Parameters
time – Date to test license validity.
- Returns
True if license is valid
- renewal_date: datetime.date#
Date of renewal of the licence.
- Type
datetime.date
- class collectives.utils.extranet.UserInfo#
User information as retrieved from FFCAM servers.
- date_of_birth: datetime.date#
User date of birth.
- email: str#
User email.
- emergency_contact_name: str#
User Emergency contact name.
- emergency_contact_phone: str#
User Emergency contact phone.
- first_name: str#
User first name.
- is_valid: bool#
True if user exists on servers.
- last_name: str#
User last name.
- license_category: str#
User license category.
- phone: str#
User phone.
- qualite: str#
User title. “titre de civilité”.
Can be M Mme Mlle. Is used to guess gender.
- collectives.utils.extranet.api: collectives.utils.extranet.ExtranetApi = <collectives.utils.extranet.ExtranetApi object>#
ExtranetApi object that will handle request to FFCAM servers.
api requires to be initialized with
ExtranetApi.init_app()
to be used.
- collectives.utils.extranet.sync_user(user: collectives.models.user.User, user_info: collectives.utils.extranet.UserInfo, license_info: collectives.utils.extranet.LicenseInfo)#
Populate a user object with user and license info from FFCAM servers.
- Parameters
user – User to populate.
user_info – User info from FFCAM server used to populate user.
license_info – License info from FFCAM server used to populate user.
Module collectives.utils.init
#
Module to initialise DB
- collectives.utils.init.activity_types(app)#
Initialize activity types
Get activity types defined in Flask application configuration (ACTIVITY_TYPES) and load it in the database. This function should be called once at app initilisation. If DB is not available, it will print a warning in stdout.
- Parameters
app – Application where to extract ACTIVITY_TYPES
- Type
flask.Application
- Returns
None
- collectives.utils.init.catch_db_errors(fct, app, *args, **kwargs)#
Catches DB error in
fct
.Usually, it is because the db is not already set up during DB setup. Thus, it is not very important.
- Parameters
fct – the function that will be called.
- collectives.utils.init.event_types(app)#
Initialize event types
Get event types defined in Flask application configuration (EVENT_TYPES) and load it in the database. This function should be called once at app initilisation. If DB is not available, it will print a warning in stdout.
- Parameters
app – Application where to extract EVENT_TYPES
- Type
flask.Application
- Returns
None
- collectives.utils.init.init_admin(app)#
Create an
admin
account if it does not exists. Enforce its password.Password is
config:ADMINPWD
- collectives.utils.init.init_config(app, force=False, path='collectives/configuration.yaml', clean=True)#
Load configuration items at app creation.
- Parameters
app – Flask app used for configuration
force (bool) – If true, force content update. Default false
path (str) – Path to YAML configuration list
clean (bool) – If True, remove configuration which is not present in the file
- collectives.utils.init.is_running_migration() bool #
Detects whether we are running a migration command.
- Returns
True if running a migration
- collectives.utils.init.is_running_migration_context(ctx) bool #
Detects whether we are running a migration command.
It has not error protection if there is no context.
- Parameters
ctx (
cli.Context
) – The current click context- Returns
True if running a migration
- collectives.utils.init.populate_db(app)#
Populates the database with admin account and activities, if and only if we’re not currently running a db migration command
- Parameters
app (
flask.Application
) – The Flask application
Module collectives.utils.jinja
#
Helpers functions that are make available to Jinja.
This module should not contains other functions than helpers_processors()
- collectives.utils.jinja.helpers_processor()#
Function used by Jinja to access utils fonctions.
- Returns
Dictionnary of
collectives.utils.time
functions.- Return type
dict(Function)
- collectives.utils.jinja.map_method(function, iterable) list #
Map an iterable to one of its method
- Parameters
function (string) – The function name
function – The interable
- Returns
the result of the iterable method
- collectives.utils.jinja.version_link(version)#
Convert a git version to an http link.
Meanwhile, it also sanitize the version since it will be included as html in the page.
- Parameters
version (string) – The version as a
git describe
format.- Returns
HTML string a the version wih its links.
- Return type
string
Module collectives.utils.mail
#
Module to handle mail
This module handles mail sending using a SMTP server. Also, it can sign with
DKIM. Conf are taken from app config
:
config.SMTP_HOST
: Hostname of SMTP serverconfig.SMTP_PORT
: Connexion port to SMTP serverconfig.SMTP_ADDRESS
: Sender address. Also used to set DKIM domainconfig.SMTP_LOGIN
: Login of SMTP serverconfig.SMTP_PASSWORD
: Password of SMTP serverconfig.DKIM_SELECTOR
: DKIM selector, usually defaultconfig.DKIM_KEY
: DKIM private key as PEM format
- collectives.utils.mail.send_mail(**kwargs)#
Wrapper for
send_mail_threaded()
- collectives.utils.mail.send_mail_threaded(app, **kwargs)#
Send a mail.
Usage example:
send_mail(subject="test", email="user@example.org", message="TEST")
If email is a list, mails are sent as Cci.
- Parameters
**kwargs – See below
- Keyword Arguments
subject (
string
) – Email subjectemail (
string
orlist(string)
) – Email Adress recipientmessage (
string
) – Email bodyerror_action (
function
) – Function to activate if email sending failssuccess_action (
string
) – Function to activate if email sending succeeds
Module collectives.utils.misc
#
Miscellaneous utils functions
- class collectives.utils.misc.NoDefault#
Dummy Class to know if default has been set in
deepgetattr()
- collectives.utils.misc.deepgetattr(obj, attr, default=<collectives.utils.misc.NoDefault object>)#
Recurses through an attribute chain to get the ultimate value.
Example: deepgetattr(role, ‘user.first_name’)
- Parameters
obj – The Object to get attribute from
attr (String) – The attribute to get. Use dots to get attribute of an attribute
default (Object) – Optionnal. If no attribute is found, return this value. If default is not defined, throw an exception
- Returns
the selected attribute
- Return type
Object
- collectives.utils.misc.is_mobile_user()#
Read browser user agent from the request and return True if a mobile browser is detected
- collectives.utils.misc.is_valid_image(file: Union[str, IO[bytes]]) bool #
Uses PIL to check whether a file is a valid image
- Parameters
file – File to verify. Path or binary stream, as accepted by
PIL.Image.open()
- collectives.utils.misc.sanitize_file_name(name: str) str #
Returns sanitized filename without characters that cannot be in a filename.
Basically removes all characters not alphanumerical, space, accentuated character, simple quote, dot, dash, commas, and underscore.
- collectives.utils.misc.to_ascii(value)#
Convert an unicode string to ASCII, drop characters that can’t be converted
- Parameters
value (str) – Input string
- Returns
ASCII string
- Return type
str
- collectives.utils.misc.truncate(value: str, max_len: int, append_ellipsis: bool = True) str #
Truncates a string so that it is no longer that a predefined length
- Parameters
value – string to truncate
max_len – maximum length of returned string
append_ellipsis – whether to put an ellipsis at the end of the string when it is truncated
- Returns
the truncated string
Module collectives.utils.numbers
#
Module for formatting number and currencies
- collectives.utils.numbers.check_phone(number: str) bool #
- Returns
True if the number if a real phone number
- collectives.utils.numbers.format_bytes(size)#
Formats a size in bytes to human-readable units
- Parameters
size (int) – The size in bytes
- Returns
A string representing the amount in human-readable form, e.g. ko, Go
- Return type
string
- collectives.utils.numbers.format_currency(amount)#
Formats a decimal amount in euros following the french locale
- Parameters
amount (
decimal.Decimal
) – The amount to be formatted- Returns
A string representing the amount in french locale, like “1,345.67 €”
- Return type
string
- collectives.utils.numbers.format_phones(phone_str: str) str #
- Returns
a regurlarly formed phone number, with proper spacing.
- Parameters
phone – A phone number
Module collectives.utils.payline
#
Module to handle connexions to Payline.
- class collectives.utils.payline.BuyerInfo(user: Optional[collectives.models.user.User] = None)#
Information about the user making the payment
- Parameters
payment – User database entry, defaults to None
- birth_date: str#
Data of birth, ptional
- email: str#
Email address, must be valid
- first_name: str#
Buyer first name
- last_name: str#
Buyer last name
- title: str#
Title, e.g. ‘M.’, ‘Mme.’, etc
- class collectives.utils.payline.OrderInfo(payment: Optional[collectives.models.payment.Payment] = None)#
Class describing an order for a payment request.
- Parameters
payment – Payment database entry, defaults to None
- amount_in_cents: int#
Amount in smallest currency unit (e.g euro cents)
- date: str#
Date and time at which the order is being made, with format dd/mm/YYYY HH:MM
- details: Dict[str, Any]#
Dictionary containing details about the order See https://docs.payline.com/display/DT/Object+-+orderDetail
- metadata: Dict[str, Any]#
Dictionnary containing free-form metadata about the order. Used in lieu of details as Payline does not seem to acknowledge orderDetails
- payment: collectives.models.payment.Payment#
Related database Payment entry
- private_data() Dict[str, Any] #
- Returns
Metadata in the Payline key-value list format
- unique_ref() str #
- Returns
An unique reference for the order
- collectives.utils.payline.PAYLINE_VERSION = 26#
Version of payline API :type: int
- collectives.utils.payline.PAYMENT_ACTION = 101#
Payment action, as per https://docs.payline.com/display/DT/Codes+-+Action 101 stand for “Authorization and Capture”
- Type
int
- collectives.utils.payline.PAYMENT_MODE = 'CPT'#
Payment mode, as per https://docs.payline.com/display/DT/Codes+-+Mode CPT stands for “Full”
- Type
string
- class collectives.utils.payline.PaylineApi#
SOAP Client to process payment with payline, refer to Payline docs
- property directpayment_client: pysimplesoap.client.SoapClient#
Cached SOAP client object to connect to Payline DirectPaymentAPI.
- disabled() bool #
Check if Payline merchant Id has been set. :return: True if PaylineApi is disabled.
- do_refund(payment_details: collectives.utils.payline.PaymentDetails) collectives.utils.payline.RefundDetails #
Tries to refund a previously approved online payment.
Will first try a ‘reset’ call (cancel immediately the payment if it has not been debited yet), and if this fail will try a full ‘refund’ call.
- Parameters
payment_details – The payment details as returned by
getWebPaymentDetails()
- Returns
An object representing the response details, or None if the API call failed
- do_web_payment(order_info: collectives.utils.payline.OrderInfo, buyer_info: collectives.utils.payline.BuyerInfo) collectives.utils.payline.PaymentRequest #
Initiates a payment request with Payline and returns the resulting token identifier on success, or information about the error
- Parameters
order_info – Information about the item being ordered
buyer_info – Information about the user amking the order
- Returns
An object representing the API response, or None if the API call failed
- property encoded_auth#
authentication string for http http_header
- get_web_payment_details(token: str) collectives.utils.payline.PaymentDetails #
Returns the details about a payment that has been previously initiated
- Parameters
token – The unique identifer returned by the
do_web_payment()
call- Returns
An object representing the payment details, or None if the API call failed
- init_app(app: flask.app.Flask)#
Initialize the payline with the app. :param app: Current app.
- payline_access_key: str#
Payline access key (to be set in payline backoffice)
- payline_contract_number: str#
payline contract number
- payline_country: str#
Payline country code
- payline_currency: str#
payment currency : euro = 978
- payline_merchant_id: str#
Payline merchant id refer to payline account
- payline_merchant_name: str#
Payline merchant name
- reload_config()#
Reads current configuration, reset client if necessary
- property webpayment_client: pysimplesoap.client.SoapClient#
Cached SOAP client object to connect to Payline WebPaymentAPI.
- class collectives.utils.payline.PaymentDetails(response: Dict[str, Any])#
Class wrapping the results of a “get payment details” API request
- Parameters
response – Dictionnary containing API call result. Must contain a ‘result’ key.
- amount() decimal.Decimal #
- Returns
The payment amount in decimal currency units
- property authorization: Dict[str, Any]#
- Returns
The dictionary corresponding to the “authorization” par of the response
- static from_metadata(raw_metadata: str) collectives.utils.payline.PaymentDetails #
Constructs a PaymentDetails object from a metadata string
- Param
raw_metadata Json-encoded metadata string
- Returns
Payment details
- property payment: Dict[str, Any]#
See https://docs.payline.com/display/DT/Object+-+payment
- Returns
The dictionary corresponding to the “payment” par of the response
- raw_metadata() str #
- Returns
the raw response dictionary as a Json string
- response: Dict[str, Any]#
Dictionary containing the raw SOAP api response for a payment details query. See https://docs.payline.com/display/DT/Webservice+-+getWebPaymentDetailsResponse
- result: collectives.utils.payline.PaymentResult#
Whether the request has succeeded, or why it has not
- property transaction: Dict[str, Any]#
See https://docs.payline.com/display/DT/Object+-+transaction
- Returns
The dictionary corresponding to the “transaction” par of the response
- class collectives.utils.payline.PaymentRequest#
Response from a payment creation request
- redirect_url#
URL on which the shopper’s browser must be redirected to make the payment.
- result: collectives.utils.payline.PaymentResult#
Whether the request has succeeded, or why it has not
- token: str#
Time stamped token that identifies the merchant’s web payment request
- class collectives.utils.payline.PaymentResult(response: Optional[Dict[str, str]] = None)#
Result returned after payline API requests. Gives information about whether the request has succeeded, or why it has not
- Parameters
response – response dictionary from SOAP endpoint
- code#
Return code, see https://docs.payline.com/display/DT/Return+codes
- is_accepted() bool #
Checks whether the call was successful
- Returns
True if successful (return message ‘ACCEPTED’), False for any other
- long_message#
long message of transaction status details
- payment_status() collectives.models.payment.PaymentStatus #
Maps the API response short message and code to a value from our PaymentStatus enum.
- Returns
The corresponding payment status
- short_message#
short message of transaction status i.e. : ACCEPTED, REFUSED, ERROR… See https://docs.payline.com/display/DT/Codes+-+ShortMessage
- class collectives.utils.payline.RefundDetails(response: Dict[str, Any])#
Class wrapping the results of a “do refund” API request
- Parameters
response – Dictionnary containing API call result. Must contain a ‘result’ key.
- raw_metadata() str #
- Returns
the raw response dictionary as a Json string
- response: Dict[str, Any]#
Dictionary containing the raw SOAP api response for a payment refund query. See https://docs.payline.com/display/DT/Webservice+-+doRefundResponse
- result: collectives.utils.payline.PaymentResult#
Whether the request has succeeded, or why it has not
- property transaction: Dict[str, Any]#
See https://docs.payline.com/display/DT/Object+-+transaction
- Returns
The dictionary corresponding to the “transaction” par of the response
- collectives.utils.payline.api: collectives.utils.payline.PaylineApi = <collectives.utils.payline.PaylineApi object>#
PaylineApi object that will handle request to Payline.
api requires to be initialized with
PaylineApi.init_app()
to be used.
Module collectives.utils.render_markdown
#
Module handling Markdown rendering.
Markdown is mainly used in event description.
- collectives.utils.render_markdown.markdown_to_html(text)#
Convert a markdown text to HTML, unless is already marked as markup-safe.
- Parameters
text (String) – Markdown text.
- Returns
Converted HTML text.
- Return type
String
Module collectives.utils.time
#
Module for time management and display.
- collectives.utils.time.current_time() datetime.datetime #
Return current time in the defined time zone.
See
config.TZ_NAME
Datetimes are stored in naive format, assumed to always be in the correct timezone. For Python to be able to compare, dates must be stripped from the tz information from our local time
- Returns
Current time
- Return type
datetime.datetime
- collectives.utils.time.format_date(value, short=False)#
Format a date. (eg “Samedi 16 février 2020”).
- Parameters
value (
datetime.datetime
ordatetime.date
) – Date to formatshort (bool) – If True, display a short version of the date as
format_date_short()
- Returns
Formatted date
- Return type
string
- collectives.utils.time.format_date_range(start, end, short=True)#
Format a range of dates without their time. (eg “Samedi 12 février 2018 au Dimanche 13 février 2018”).
- Parameters
start (
datetime.datetime
ordatetime.date
) – Range start date.end (
datetime.datetime
ordatetime.date
) – Range end date.short (bool) – If True, display short version of the dates as
format_date_short()
- Returns
Formatted date range.
- Return type
string
- collectives.utils.time.format_date_short(value)#
Format a date. (eg “Sam 16 février”).
- Parameters
value (
datetime.datetime
ordatetime.date
) – Date to format- Returns
Formatted date
- Return type
string
- collectives.utils.time.format_datetime(value)#
Format a date + time. (eg “Samedi 16 février 2020 à 8h00”).
- Parameters
value (
datetime.datetime
) – Date to format- Returns
Formatted date or ‘N/A’ if value is None
- Return type
string
- collectives.utils.time.format_datetime_range(start, end)#
Format a range of dates. (eg “Samedi 12 février 2018 à 08:00 au Dimanche 13 février 2018 à 15:00”).
If
start
andend
are the same day, day is not repeated.If
start
andend
are the same, it is not treated as a range.If
start
andend
are at 0h00, time is not formatted.
- Parameters
start (
datetime.datetime
) – Range start date.end (
datetime.datetime
) – Range end date.
- Returns
Formatted date range.
- Return type
string
- collectives.utils.time.format_time(value)#
Format a time. (eg “8h12”).
- Parameters
value (
datetime.datetime
) – Date to format- Returns
Formatted date
- Return type
string
- collectives.utils.time.fr_months = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']#
Months in French.
Server may not have fr_FR locale installed, for convenience, we simply define months names here
- collectives.utils.time.fr_short_months = ['jan.', 'fév.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sep.', 'oct.', 'nov.', 'déc.']#
Months abbreviations in French.
Server may not have fr_FR locale installed, for convenience, we simply define months abbreviations here
- collectives.utils.time.fr_week_days = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']#
Day of week in French.
Server may not have fr_FR locale installed, for convenience, we simply define days of weeks names here
- collectives.utils.time.parse_api_date(date_str: str) datetime.datetime #
Parse a date from client API calls
Expected format is YYYY-MM-DD + optional time/tz Returns a naive datetime object in the server timezone Returns
None
if date_str is invalid
- collectives.utils.time.server_local_time()#
Alias of
current_time()
Module collectives.utils.url
#
Module which contains various helping functions for url management.
- collectives.utils.url.slugify(value)#
String normalisation.
Normalizes string, converts to lowercase, removes non-alpha characters, and converts spaces to hyphens.
From Django’s “django/template/defaultfilters.py”.