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

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 server

  • config.SMTP_PORT: Connexion port to SMTP server

  • config.SMTP_ADDRESS: Sender address. Also used to set DKIM domain

  • config.SMTP_LOGIN: Login of SMTP server

  • config.SMTP_PASSWORD: Password of SMTP server

  • config.DKIM_SELECTOR: DKIM selector, usually default

  • config.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 subject

  • email (string or list(string)) – Email Adress recipient

  • message (string) – Email body

  • error_action (function) – Function to activate if email sending fails

  • success_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 or datetime.date) – Date to format

  • short (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 or datetime.date) – Range start date.

  • end (datetime.datetime or datetime.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 or datetime.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 and end are the same day, day is not repeated.

  • If start and end are the same, it is not treated as a range.

  • If start and end 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”.