Commit Graph
9 Commits
Author SHA1 Message Date
Noe Antoine 69277f846e [IMP] website_slides : add attendee status, improve invitations to course
RATIONALE

Improve and make easier the invitations on courses, whatever the enroll policy.
The goal is to increase the number of attendees easily

PREVIOUS BEHAVIOUR

Before this commit, the attendees of a course were always enrolled.
No distinction existed. Inviting partners meant enrolling them at once, even if
they did not want to join. Also, invitations to a 'members only'-visibility
course were a problem since the invited member could not reach the course page
if not logged in. Therefore the invitation link in invitation mail was often
not usable (403 error). The invitation link did not act as a user creation link
if the partner was not linked to any user

PURPOSE OF THIS COMMIT

After this commit, attendees to a course can either be enrolled (default behavior)
or have pending invitation, allowing to preview the course before joining it.
Also, the invitation links redirect the partner according to their (potential)
linked user, their log in status and the ACL's. All course completion and
invitation status are covered by the new member_status selection field for attendees:
- 'invited' : member with pending invitation
- 'joined' : enrolled member, not started
- 'ongoing' : enrolled member, started but never finished
- 'completed' : enrolled member who completed the course

A) INVITATIONS: ADD ATTENDEES and INVITE

The way to add and invite attendees to a course attendees in now centralized in
two options, the buttons for which being added on the course forms / kanban cards
dot menu. On the attendee list view coming from a course, only the [NEW] button
is shown (= ADD ATTENDEES). Using the buttons will open the invite wizard. (the
same one, the difference being the value of the new boolean enroll_mode)

In both cases, when sending a link to a given partner, it will contain both a hash
based on the couple (partner_id, channel_id) and the value of partner_id. This will
allow giving access to the invited partner even if not logged in and for all visibilities

    1) INVITE: copy the course link OR add partners as 'invited' + send them an email

    This new option is meant for promotional purposes. It will give a preview access
    to potential new members, but will not add them as enrolled. It will send an
    email to partners not already in the active attendees, to invite them to check
    the course

    Clicking the invitation link will lead them on the course page, where a [BANNER]
    will explicitely ask the invited partner to LOG IN or to SIGN UP depending on
    them having a user or not, and explain them that they must first be logged to
    access previews and join / buy the course. Before that, they can only see a
    [PREVIEW] of the course: browse the list of contents (i.e. categories are available),
    to allow them to see whether the course is of interest (forum / reviews are hidden
    too). If they are logged, or once they are logged, they will see the course as if
    it were public, no matter its visibility. (they can join - buy - browse previews)

        [LOG IN / SIGN UP] links (see /identify route): they will bypass the value of
        the 'Free Sign Up' setting and route will 1) check the invitation values
        (hash, partner_id), and that there exists a matching attendee for the current
        course. 2) prepare the signup / login. This prevents the invited partner from
        being locked outside of the course, not being able to join it (as not able to
        create user)

        ENROLL policies:
        -> 'on invite': inviting is considered as granting access. The partner will
            not have to ask for access again, but will be able to join in directly.
        -> 'on payment': users will NOT be able to join the course without buying it.
            The buy button on the course page will be replace by [LOG IN / SIGN UP].
            We do not want them to buy a course and potentially be locked out.
            (further work should deal with the generic case of this issue.)

    2) ADD ATTENDEES: add partners as 'joined' and send them an email

    This option is the same as what existed before: partners are added as enrolled
    attendees and invited by email. When they click on the link, they will be able
    to create an account if they do not have a user, or to log in if they have one,
    whatever the visibility, BEFORE being redirected to the course. They are enrolled,
    so they need to log in in order to use the course. 'invited' members will also be
    enrolled and upgraded to 'joined' and sent a joining email.

    3) About (archived) ATTENDEES and COMPLETION:

    (From task 2199207 on, attendees are now archived instead of deleted, in order to
    keep track of progression. Status and completion updates must be dealt with when
    using invitation / adding attendees)

    Now, [ONCE 'COMPLETED', ATTENDEES REMAIN SO], whatever slides they mark as
    uncompleted / completed or is created / archived on the course. Karma for
    finishing the course is won only once. test_attendee_course_completion_values
    is added. Even archived, we never recompute completion (remains 100) and status
    of 'completed' members. The same is true for 'invited' members, we do not make
    any update. This means that archived 'invited' members can have positive completion.

    In addition to the obvious (recompute status and completion when completing a slide
    as 'joined' or 'ongoing'), we only recompute member_status and completion when
    enrolling an attendee as 'joined', in the method _action_add_members with
    member_status = 'joined'. We explicitely recompute the values then. This happens
    on joining (possibly from an 'invited' state), on adding members as 'joined', or
    when unarchiving a record at least 'joined'.

        3.1) Archived with progress:

        When inviting an archived member with progress, we set their member_status
        to 'invited', and unarchive them. It means that completion could be > 0 for
        active (or inactive) 'invited' members. When enrolling them, we set them to
        'joined' but we need to recompute their completion to update the completion
        value (there may have been changes in the contents) and their member_status
        accordingly.

        3.2) Archived as 'invited' (no progress):

        When inviting them, we simply unarchive them. When enrolling them, they are
	unarchived and set to 'joined', status and completion being then recomputed.

	3.3) A complex and full example.

	Attendee A completed the course C, having 4 contents. member_status is
	'completed' and completion = 100. Then A leaves the course and is archived.
	Later, C gets 1 more content. The member_status and completion do not change.
        A is invited. Its member_status is now 'invited', and completion 100. 3 contents
	are archived. Again, values do not change. A clicks the link and enrolls. It
	is added as 'joined' and _recompute_completion is called. completion is set
	to 50% and status to 'ongoing'. As the completion was 100 but is not anymore,
        the karma for completing the course is lost. They see the new slide and are
	set to completion = 100 and 'completed', winning the course karma back.

B) ACCESS RIGHTS UPDATES

    1) PREVIEW:
    In order to give access to 'members only' courses even without logging in, we
    use the url parameters invite_hash and partner_id. They can access as sudo the
    course but _can_publish and _can_upload stay False. Categories can also be clicked.
    No slides are accessible, only the course page, checking the access values each time
    the channel route changes. See _get_channel_values_from_invite for all the checks on
    the direct invitation parameters invite_partner_id and invite_hash)

    The breadcrumbs and routes are updated to use channel_id instead of slug (since it
    would lead to a 403 error) The course_id routes should only be used in the context of
    an invitation. (generic or direct). Also, the main channel route now checks the access
    rights to the course and redirect to /slides if the access is not granted, useful for
    the generic invitation.

    2) ACLS
    - Slides: invited members to 'members only' courses now have the same access as
    anyone for public courses: previews and categories, once logged in.
    - Course: invited members have access to the course
    - Self-enroll: 'invited' member can self-enroll to 'on invite' courses, this is done
    with a sudo on the /join route.

    3) About ARCHIVED ATTENDEES. [FIX] (tests included)

    (*) In task 2199207, the ACL's were not updated to prevent archived members to have the
    same rights as if they were active. This is because the active value is not tested by
    default in rules. It is done by changing partner_ids into a computed field search method.

C) MODELS

    1) SLIDE.CHANNEL.PARTNER
    - new: invitation_link computed field. It generates invite_hash with course and
    partner_id and contains invite_partner_id as well, used for verifications.
    - recompute_completion will always recompute the completion %. However, member_status
    will only be updated if not currently 'invited' and currently active. One should write
    'joined' on attendees before in order to see the status of an 'invited' member updated.

    2) SLIDE.CHANNEL
    - channel_partner_ids / partner_ids keep the meaning of enrolled attendees/partners.
    partner_ids is now replaced with a compute field, and channel_partner_ids has a
    domain on member_status. search method is implemented (*)
    - new: channel_partner_all_ids / partner_all_ids also includes invited attendees /
    partners. partner_all_ids is also a computed field. search is implemented (*)
    - new: is_member / is_member_invited are computed fields to indicate the current
    user's membership status to the course

    - _action_add_member is removed and _action_add_members now centralizes the logic of
    adding an attendee. It will now return all NEW ACTIVE MEMBERS for the given status.
    The ones unarchived, the ones created, and the ones enrolling from 'invited' state
    for parameter = 'joined'. Therefore, reinvitation of 'invited' members in dealt with
    in action_invite in slide.channel.invite model as they will not be returned.

    3) RES.PARTNER
    As a rule of thumb, the fields and display are the same as before. They cover the
    courses partner is enrolled to. Changes are done to ease the search on partners:
    - slide_channel_ids keeps the same meaning: the courses the partner is enrolled to.
    It is changed to a compute field since we do not want to consider 'invited'
    members. search method is implemented
    - new slide_channel_all_ids contains all the courses: the ones the partner is
    invited to or enrolled in
    - Most compute methods are centralized in a single method and read_group is used.

D) VIEWS AND OTHER MAIN CHANGES

INVITE WIZARD
    - As a course can be only shared via its generic link, the invite wizard now has
    a [TOGGLE] 'send_email' that is visible for public courses and allow to either
    copy and share the generic link, or, if toggled, show and use the email composer.
    - if course is not published, a warning alert message is shown at the top. In
    order to have a clean UI, the form is restructured using a sheet
    - The course field is now hidden and is directly shown in the title of the wizard

ATTENDEE LIST VIEW
    - [NEW] button when coming from a course (i.e. not for reporting), acting as the
      [ADD ATTENDEES] button
    - new columns

OTHER VIEWS
    - Pivot and graph reporting views are added. A default member_status groupby too,
    on all reporting views. The % of completed slides is not used as measure on pivot
    view. However, it is on the graph view to compare completion of different members
    easily. Avg is used as an operator, as sum of percentages does not mean much here
    - Attendees kanban view update and new filters / group by's
    - Quicksearch 'Tags' and 'Responsible' on slide.channel model

MISC
    - Use 'course' instead of 'channel' in readable labels
    - Use 'attendee' instead of 'member' in readable labels
    - Error mgmt: clicking the invitation link may lead to an error, as well as
    accessing a course without the rights. The user will be redirected to the main
    /slides page with the appropriate error message
    - Add a new template similar to the one used to join a course, but for the
    invitation action
    - New template for the popup appearing when joining a course. (Login or Signup)
    - Use fstrings and t-attf when possible
    - Use native js instead of jquery
    - New placeholder if no contents on course page in the front-end
    - Markup is used when possible

E) Invitation Expiration

As the invitation could be used as a promotion tool, there may be a lot of records
created as 'invited'. In order to monitor that number, we use a garbage collector.
It will remove attendees as 'invited', active or not, with completion = 0 and invited
for the last time at least THREE MONTHS before (at least invited once). Also, an
invitation older than 3 months will become expired and will not grant access to
'invited' members.

In order to track the invitation dates, a new field last_invitation_date is added to
the slide.channel.partner model. Every time one invites an attendee, it is set to the
current date. One can reinvite attendees and send them an email more than once. This
may prevent the invitation to be collected by the GC. If not set, last_invitation_date
is considered as expired.

F) TESTS and TOURS

Extensive tests and tours are added for the different new flows coming from
this new distinction between joined and invited members, and invitation flows.
They test functionality, UI, security (access rights) and model correctness.

--- Links ---
Task-2508019
COM PR - odoo/odoo#70291
UPG PR - odoo/upgrade#2572

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2023-05-04 19:09:49 +02:00
amdi-odoo 112283081b [FIX] website_slides: fix typo
Purpose
=======
Fix typo in the mail template data used for
a completed course.

Specifications
==============
Adding a 's' to 'Congratulation' on the template
subject.

Task-3026717

closes odoo/odoo#104737

X-original-commit: ea535166692ed95b3878717f3e003e23ce8c9fc5
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2022-11-02 15:34:50 +01:00
Dossogne Bertrand 7c4da16b59 [IMP] mail, various: improve mail template usability
Allow our users to modify mail template more easily

- make the list accessible from the settings
- give them a link to update relevant views to update header/footer
- make the list and form of templates more readable
- add a description on templates, allowing to describe their usage

In order to better filter templates, a new category field is added that
is computed based on active flag, description being set and the template
having an xml ID. Master templates are active, with a description and an
xml ID.

Update master data to add description on some templates.

task-2944770

closes odoo/odoo#101730

X-original-commit: dfa867343ee8842f3f127ac62584fd471b41dde1
Related: odoo/enterprise#32079
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2022-10-04 09:55:46 +02:00
Nikunj Ladava 7d66dcbf54 [IMP] website_slides: improve design of share pages in elearning
PURPOSE

Globally improve user experience when sharing content from the e-learning app.
This includes new sharing options, allowing to share to multiple emails, split
the sharing template from slide and course, etc...

SPECIFICATION

- added two more options 'WhatsApp' and 'Pinterest' to share snippets.
- we converted the email type of input for 'Share by email' to text,
  so we can enter multiple emails to share and also add validation
  in the controller for this input text input.
- We improved the design of the share modal by making sure that the full URL
  for sharing link is visible and rearranged the UI fields of
  'Share' nav-tab on non-fullscreen content (if there is
  embed code, the sharing by email and embed code will still be on
  the single row).
- Improved the share modal of the channel by adding an email field in it to
  Share the channel through the mail.
- New field name 'share_channel_template_id' for channel template
  in 'slide.channel' modal and also added _send_share_email method
  in it and email template for sharing channel through the mail, and
  also added the dedicated route for sharing the channel.
- New share button is added on the top of documents in the slide (which
  previously was in the tab below the content).

task- 2627364

Part-of: odoo/odoo#78139
2022-09-02 14:17:40 +02:00
Pierre-Yves Dufays db63c03af9 [IMP] website_slides: display a user-friendly error message when accessing an
unauthorized course content

Display a user-friendly error message when a user access an unauthorized
course content.

Specifications:

When a non-authorized course content is accessed, instead of a 403 error page,
redirect to the course page with a small notification saying
"You need to join this course to access ContentName"

Technical remarks:

As the slide URL may lead to a 403 if the user has not access to the course and
we didn't want to change that route, we have decided to share URL with a
specific route when the resource is protected (is_preview = False):
slides/slide/<int:slide_id>/share

To make available that new URL in the templates and to the client, a computed
field website_share_url has been added to the channel and slide model.

Note that when checking the access rule, a MissingError can be triggered if for
example the content has been deleted. In that case the user will be redirected
to a 404 and 2 reads are performed but the code is more generic.

Task 2742087

closes odoo/odoo#83935

Related: odoo/upgrade#3280
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2022-03-16 09:58:42 +01:00
Aurélien Warnon ab0b36e8a5 [REF] website_slides: rename slide.slide fields
This commit simply applies the following renames in the slide.slide model:

- 'datas' is renamed into 'binary_content'
- 'slide_type' is renamed into 'slide_category'

This changes intend to ease the next bug refactoring of the website_slide
module content management.

There should be no functional changes applied in this commit.

Task-2510174

Part-of: odoo/odoo#71477
2021-11-30 15:21:47 +00:00
Nicolas Bayet 4813f42997 [IMP] mail,*: replace jinja with qweb
Jinja as a templating engine was problematic in differents respect:
- introduce external dependency to Odoo (less controll)
- add another templating mechanism in the stack
- specific feature in qweb cannot be reused
- difficulty in rendering easily editable templates
- more knowledge required with no betterment

By replacing jinja with qweb we can now build tools to edit a qweb
that will work with the previously jinja encoded document
(essentially `mail.template` records).

There is a catch however. Some email fields (eg. email_to) used jinja
syntax for rendering dynamic variables (ie. ${object.something} and
${object.something_that_should_not_be_escaped | safe}).

We still want user to use dynamic variables for some char fields (eg.
subject, from, to, ...). We made a new rendering engine called
"inline_template" that will render an expression enclosed by `{{` and
`}}`.

To be able to edit the templates from the backend interface, a
plugin to the Odoo editor has been made for seamlessly edit the
document.

This qweb plugin includes:
- make dynamic variables (eg. `<t t-out="variable"/>`) not editable
  (for preventing the user to shoot himself in the foot)
- group and hide related logical branching (ie. t-if, t-elif, and t-else)
  in order to see only one at once
- a floating select input to switch visibility of a particular logical
  branching

Task-27033

X-original-commit: odoo/odoo@68182baff4
Part-of: odoo/odoo#77377
2021-09-28 23:42:54 +00:00
Munaf Khan 292ffeec00 [FIX] various: avoid scroll for button(s) within mail templates
Right now, for notifications handled by odoo (which are being displayed on
discuss app / object chatter), few of the buttons have unexpected scroll
(mostly the CTAs that redirect to record / portal views) and ruins the UI.

This commit fixes the issue by improving such templates by using proper
paddings on the button.

TaskId:2518863

closes odoo/odoo#70083

Related: odoo/enterprise#18225
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
2021-06-15 08:34:37 +00:00
Thibault Delavallée f2dd80677c [MOV][IMP] website_{profile/slides}: reorganize qweb / jinja templates used for mailing
PURPOSE

Clean organization of templates in odoo apps: mail.template records in data,
qweb templates (views) used directly in code, notably using post with view.
Purpose is to ease future improvements in posting based on templates.

SPECIFICATIONS

  * move those templates in their own file to ease their discovering and
    maintenance;
  * put them into data (as those are not views even if it contains qweb)
  * guidelines are now :

    -> Qweb templates should be in data/mail_templates.xml;
    -> mail.template records should be in data/mail_template_data.xml;

  * put their declaration in no update when not done if template has no
    technical code or complex dependency on underlying code;
  * move found mail data (mail.message.subtype or mail.activity.type) records
    in a mail_data file that should contain only "core" records linked to mail;

LINKS

Task ID-2375767
COM PR odoo/odoo#61814
ENT PR odoo/enterprise#14775
UPG PR odoo/upgrade#1936
2020-11-25 12:31:09 +00:00