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 pagewith 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) 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) 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)#
Initializes the API for the given Flask app
- property soap_client: 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() 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) 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: 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: 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: 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: User, user_info: UserInfo, license_info: 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
adminaccount 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.timefunctions.- 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 describeformat.- 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 (
stringorlist(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: object, attr: str, default: Any = <collectives.utils.misc.NoDefault object>, resolve_method: bool = False) Any#
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 – The attribute to get. Use dots to get attribute of an attribute
default – Optionnal. If no attribute is found, return this value. If default is not defined, throw an exception
resolve_method – Whether to call the attribute if it is a method
- Returns:
the selected attribute
- 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: 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: 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: 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
- 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: 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: PaymentDetails) 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: OrderInfo, buyer_info: BuyerInfo) 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) 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)#
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: 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#
- 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) 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: 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: 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: 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() 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: 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: 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.add_months(months: int, from_date: date | None = None) date#
Add months to a date.
- Parameters:
from_date – date from which to add months (default: today)
months – number of months to add (may be negative)
- Returns:
new date with months added
- collectives.utils.time.current_time() datetime#
Return current time in the defined time zone.
See
config.TZ_NAMEDatetimes 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.datetimeordatetime.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.datetimeordatetime.date) – Range start date.end (
datetime.datetimeordatetime.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.datetimeordatetime.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
startandendare the same day, day is not repeated.If
startandendare the same, it is not treated as a range.If
startandendare 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.get_ffcam_year(year: date) int#
- Returns:
the FFCAM year (four digits) for a given date.
EG: 5th of May 2023 -> 2022 15th of September 2023 -> 2023
- collectives.utils.time.parse_api_date(date_str: str, day_only: bool = True) 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
- Parameters:
day_only – If true, sets time portion of datetime to midnight
Returns
Noneif date_str is invalid
- collectives.utils.time.server_local_time()#
Alias of
current_time()
- collectives.utils.time.ttl_cache(ttl: int = 10)#
Decorator to cache function results for a given time-to-live (TTL) in seconds.
- Parameters:
ttl – Time-to-live in seconds
- Returns:
Decorated function with caching
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”.