Skip to content

Back end for link sharing #759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 12, 2019
Merged

Back end for link sharing #759

merged 2 commits into from
Aug 12, 2019

Conversation

Andrewdt97
Copy link
Contributor

@Andrewdt97 Andrewdt97 commented Aug 9, 2019

Overview:
In order to better support users without emails and to streamline project sharing, it was determined that we should allow project managers to create invite links, which, upon accessing, add a user to a project with a specified role. This PR includes all of the back-end support for this link sharing. It includes three major partitions:

1. Creation and management of share link:
There are four new API calls related to the shareable link

  • 'project_createInviteLink', [defaultRole<string>]: link<string>
    • Takes a roleKey and returns the invite Url
  • 'project_getInviteLink', []: link<string>
    • Returns the current invite Url
  • 'project_disableInviteToken', []: void
    • Makes the inviteToken an empty string, thereby disabling it
  • 'project_updateInviteTokenRole', [newRole<string>]: void
    • Given a roleKey will update the role a user is assigned when joining via the link

All API calls require Domain::USERS + Operation::EDIT permission except project_getInviteLink, which requires Domain::PROJECTS + Operation::VIEW permission. These calls invoke ProjectCommands that manipulate a ProjectModel's new inviteToken object.

2. Joining via the link:
All links point towards https://<app>.org/invite/<invite code>. When such a link is accessed, the server looks up a project with that invite code. If it is found and the user is logged in, the user is added to the project and redirected there. If it is found and the user is not logged in, there are taken to the login page with a message encouraging them to register. The invite code is tracked within $app['session'] and is processed when the projects or lexicon apps are next accessed. If the project is not found, the user is show an error message on whatever page is appropriate to take them to based on their log-in status.

3. Miscellaneous Refactors:
The following changes are also included to support the above features:

  • The NoticeService now has an checkUrlForNotices() method which checks the Url for base-64 encoded messages in the errorMessage, infoMessage, and successMessage parameters.
  • The login page has been turned into an angular component in order to use the NoticeService

Screenshots:
image
Login page displaying a notice that a project could not be found with a given invite link.

image
Successfully being added to a project after signing up

Tests:
All PHP unit tests run (including new ones for the ProjectCommands)

E2E tests fail at Update and store different username. Login with new credentials. My guess is that this is due to the fact that migrating to an angular component from Silex on the login page no longer saves the username when logging out and logging back in. I am looking into as you read this.

If you wish to manually test the invite link. /invite/test is set up to create a new project and handle it's invite code. Use branch feature/linkSharingBackEndTestable.

Ideas for continued development:

  • Increase/test support for non-Lf apps (if desired)

This change is Reviewable

@Andrewdt97 Andrewdt97 force-pushed the feature/linkSharingBackEnd branch from db09a5f to 03cb4d5 Compare August 9, 2019 04:27
@Andrewdt97 Andrewdt97 force-pushed the feature/linkSharingBackEnd branch from 03cb4d5 to 989f348 Compare August 9, 2019 04:50
Copy link
Collaborator

@megahirt megahirt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking very close to being done! You're almost there :)

Reviewed 13 of 15 files at r1, 2 of 2 files at r2.
Reviewable status: all files reviewed, 9 unresolved discussions (waiting on @Andrewdt97)


src/Api/Model/Shared/InviteToken.php, line 10 at r1 (raw file):

{

    public function __construct() {

I think you can just leave out the empty constructor...not required.


src/Api/Model/Shared/ProjectModel.php, line 231 at r1 (raw file):

        if(!$validRole)
        {
            throw new ResourceNotAvailableException('Project ' . $projectId . '\'s invite token is associated with nonexistant role '

spelling correction to "nonexistent" :)


src/Api/Model/Shared/ProjectModel.php, line 343 at r1 (raw file):

            $this->inviteToken->defaultRole = $newRole;
        } else {
            throw new \InvalidArgumentException("A nonexistant role tried to be linked to an invite token.");

"nonexistent"


src/Api/Model/Shared/ProjectModel.php, line 468 at r1 (raw file):

readByProperty('inviteToken.token', $token);

does this actually work? Cool! I didn't realize that you could address a sub-property in the readByProperty method - I learn something new everyday...


src/Api/Model/Shared/Dto/RightsHelper.php, line 116 at r2 (raw file):

                return true;
            case 'project_getInviteLink':
                return $this-userHasProjectRight(Domain::USERS + Operation::EDIT);

I'm thinking that the permissions for project_getInviteLink should actually be less than "manager" which is what this currently is. I think that
project_getInviteLink should have a base permission of project user, since anyone should be able to get the link once it is enabled, and not just managers. This function should simply return an existing link stored in the database, and generate one if it doesn't exist.

Seeing this line here now reminds me that we also need a project_generateLink or something similar.


src/angular-app/bellows/apps/public/login/login-app.component.ts, line 10 at r2 (raw file):

  $onInit() {
    this.notice.checkUrlForNotices();

This feels like it should be in the $onInit() of the notice component itself, that way we don't have to remember to call this for every controller that uses the notice service, and also every instance of the notice component will automatically gain this feature.


src/Site/Controller/App.php, line 31 at r2 (raw file):

($appName == LfProjectModel::LEXICON_APP || $appName == 'projects')

We probably should not make this Lexicon app specific.

This whole section might fit better in Auth.php immediately after a successful login.


src/Site/Controller/Validate.php, line 16 at r2 (raw file):

class Validate extends Base
{
    public static function check(Application $app, $validateKey = '')

should be public static function


src/Site/Controller/Validate.php, line 37 at r2 (raw file):

    }

    public function processInviteAndRedirect(Application $app, $inviteToken = '')

should be public static function

@megahirt megahirt force-pushed the feature/linkSharingBackEnd branch from d7f432a to c19468c Compare August 12, 2019 04:08
Add InivteLink object to ProjectModel

.

Add ProjectCommands for invite link generation

Add API end points for link sharing operations

Logged-in and valid token redirection

Skeleton for proper redirection

Display messages from URL

Error messages for invalid invite link

Make checkUrlForNotices() self-contained

Also consumes the error message

Add Array.includes polyfill to fix lots of Bugsnag errors

Bugsnag was seeing errors mainly from IE11 and UC Browser.

Also alphabetize the list of polyfill imports to make TSLint happy.

add new build-agent to hosts

tag this so it doesn't run for build-agents

add buildagent install shell script

fix hostnames

Remove references to temp/jsonSessionData

Remove references to temp/jsonSessionData

Rendered entries now show correct part of speech

Previously the optionLists data wasn't making it all the way to the
dc-rendered component, so the component couldn't look up proper
abbreviations for parts of speech and had to resort to using the key
instead. This was mostly invisible for projects that had an English
language user interface, but for non-English interfaces the English
part-of-speech abbreviations were being wrongly shown. Fixed.

This should fix https://jira.sil.org/browse/LF-319

Invite token is tracked through authentication process

Polish for back end link sharing

Convert login to angular component

Return id instead of model when looking up by invite token

And minor polish

Add FlashBag support to Login app to pass E2E tests

Return id instead of model when looking up by invite token

And minor polish

Distinguish between createInviteLink and getInviteLink

Merge master
@megahirt megahirt force-pushed the feature/linkSharingBackEnd branch 3 times, most recently from 57de325 to 18726c8 Compare August 12, 2019 07:48
Copy link
Collaborator

@megahirt megahirt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 5 of 7 files at r3, 4 of 4 files at r4, 2 of 2 files at r5.
Reviewable status: all files reviewed, 8 unresolved discussions (waiting on @Andrewdt97)

Also added PHP Code Sniffer as dev dependency for use in VS Code
project_getInviteLink can be accessed by project members

The specific API security checks will be done inside the method
@megahirt megahirt force-pushed the feature/linkSharingBackEnd branch from 18726c8 to a19a10e Compare August 12, 2019 08:17
Copy link
Collaborator

@megahirt megahirt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have finished Andrew's PR on his behalf, and we will now carry on with the feature on Brant's branch.

Reviewed 5 of 5 files at r6.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved


src/Api/Model/Shared/InviteToken.php, line 10 at r1 (raw file):

Previously, megahirt (Christopher Hirt) wrote…

I think you can just leave out the empty constructor...not required.

done.


src/Api/Model/Shared/ProjectModel.php, line 231 at r1 (raw file):

Previously, megahirt (Christopher Hirt) wrote…

spelling correction to "nonexistent" :)

done.


src/Api/Model/Shared/ProjectModel.php, line 343 at r1 (raw file):

Previously, megahirt (Christopher Hirt) wrote…

"nonexistent"

done.


src/angular-app/bellows/apps/public/login/login-app.component.ts, line 10 at r2 (raw file):

Previously, megahirt (Christopher Hirt) wrote…

This feels like it should be in the $onInit() of the notice component itself, that way we don't have to remember to call this for every controller that uses the notice service, and also every instance of the notice component will automatically gain this feature.

done.


src/Site/Controller/App.php, line 31 at r2 (raw file):

Previously, megahirt (Christopher Hirt) wrote…
($appName == LfProjectModel::LEXICON_APP || $appName == 'projects')

We probably should not make this Lexicon app specific.

This whole section might fit better in Auth.php immediately after a successful login.

Removed lexicon-specific code.

After investigation, the Auth.php file doesn't seem to contain the logic to determine if a login succeeded or not, which is what we need for this method. Leaving in App.php with a todo notice.


src/Site/Controller/Validate.php, line 37 at r2 (raw file):

Previously, megahirt (Christopher Hirt) wrote…

should be public static function

I stand corrected. These are public controller methods that are mapped to Silex routes in index.php and it is expecting them not to be static.

@megahirt megahirt merged commit f15efc1 into master Aug 12, 2019
@megahirt megahirt deleted the feature/linkSharingBackEnd branch August 12, 2019 08:22
@megahirt
Copy link
Collaborator

InviteLink PHP API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants