Skip to content

[policies] Add infrastructure to track user decisions to policies #9818

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

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

skarya22
Copy link
Contributor

@skarya22 skarya22 commented May 28, 2025

Brief summary of changes

  • Added policies table for projects to implement policies that users must agree to to use certain modules or to request a LORIS account.
  • Configurable so that you can choose the following:
    • Which module it should be for
    • Should it be a accessible by a button in the header
    • Should the user be forced to accept the policy before being able to access this module?
    • How long in between accepting the policy do they have to accept it again?
If there is a policy for the login module
image image image
If there is a policy for a non-anonymous module, and HeaderButton = 'Y'
image

Testing instructions (if applicable)

  1. Two policies have been added to raisinbread, confirm they are present SELECT * FROM POLICIES
  2. Open the Dataquery module, you should be prompted to accept the terms of use
  3. Select Decline, and you should be sent to the LORIS homepage
  4. Confirm the decision was saved for your user select * from user_policy_decision
  5. Open the module again and press Accept, you should be able to access the module now. Confirm your decision was saved.
  6. Exit the module, and re-open it, confirm that it does not prompt you for a policy again.
  7. Modify user_policy_decision and change it to that you accepted the policy 8 days from today
  8. Re-open the module and see that it prompts you to accept the terms of use again
  9. Log out and go to the Request Account page
  10. Enter all the details but do not press Terms of Use
  11. Try to submit and see that it makes you view the terms of use first
  12. View the terms of use and try again
  13. Try to create your own policy for a module and confirm that it behaves how you expect

Link(s) to related issue(s)

  • No issue, but both CCNA and EEGnet had their own implementations, this will reduce the number of overrides

@github-actions github-actions bot added Language: SQL PR or issue that update SQL code RaisinBread PR or issue introducing/requiring improvements to the Raidinbread dataset Language: PHP PR or issue that update PHP code Language: Javascript PR or issue that update Javascript code Module: login PR or issue related to login module labels May 28, 2025
@skarya22 skarya22 added Project: CCNA Issue or PR related to the CCNA project Project: EEGNet Issue or PR related to the EEGNet project labels May 28, 2025
Copy link
Collaborator

@driusan driusan left a comment

Choose a reason for hiding this comment

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

I like the idea of this and did a first pass at skimming it. I think the structure should be reworked.

In addition to the changes requested, on a high level I think it would make sense to have a "Policy" class to group the behaviour together rather than everything being ad-hoc strings and Utility functions and htdocs files.

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE `policies`;
LOCK TABLES `policies` WRITE;
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (1,'dataquery_example','v1',49,7,'D','By using this Data Query Tool, you acknowledge that you know it is in beta and may not work as expected. You also agree to use it responsibly and not to misuse the data.','Terms Of Use','Y','Terms Of Use','Y','Yes, I accept','Decline','2025-05-28 10:54:21','2025-05-28 10:54:21');
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm confused by the fact that the example in the database is for the data query tool but the code being changed is for request account

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are two example policies. The one for the login page is right under this.

The one for dataquery does not require any edits to the module as it is inherited from NDB_Page and will work the same for all pages / modules. So any module just needs to have an entry in policies for it to show up.

I had to make changes to request account to enforce that if there is a policy there it is enforced where you have to view it to request an account

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To clarify this a bit further as well, as mentioned there are two example policies in this PR.

  1. A pop-up policy for the DQT that both pop-up when the module is opened, but is also re-openable whenever you press on Terms of Use in the header while the module is open. This behaviour is easily reproducible in any module just through sql.
  2. A policy that is tracked on the login page when a user is requesting an account. It's a different use case than the regular pop-up policies since we need a button in request account rather than having it automatically pop-up or having a button in the header. So for this one we need to manually add the PolicyButton, versus the other implementation where the policy is enforced / added through SQL.

@regisoc
Copy link
Contributor

regisoc commented Jul 7, 2025

@jeffersoncasimir let me know if you have time for this one, else re-assign it to me.

@jeffersoncasimir
Copy link
Contributor

@regisoc I don't think this is ready for review. Not passing tests, no changes since previous review and likely needs rebase

@skarya22 skarya22 added the State: Needs work PR awaiting additional work by the author to proceed label Jul 10, 2025
@skarya22
Copy link
Contributor Author

@jeffersoncasimir sorry about that -- you're right it went off my radar when I went on vacation. I'll fix it up and then request a review! Thanks

@skarya22 skarya22 removed the State: Needs work PR awaiting additional work by the author to proceed label Jul 15, 2025
@skarya22
Copy link
Contributor Author

@jeffersoncasimir thank you for your patience -- it's ready for review now!

There is a test failing, but it seems unrelated to the PR:
image

Copy link
Contributor

@jeffersoncasimir jeffersoncasimir left a comment

Choose a reason for hiding this comment

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

Works nicely. Likely ready for approval after revision.

Please make sure to add policy_tracker to the modules table in the patch, the -01 schema, and RB.

My interpretation of the testing instructions is that it acts as somewhat of a safeguard to a module, but it doesn't re-prompt when declined, and it can easily be bypassed. I can decline the RB dqt prompt, be sent the home page, but then go back to the dqt and use it normally and unprompted, as if nothing happened. Is it intended do a be a bit more consequential?

PolicyRenewalTime INT DEFAULT 7,
PolicyRenewalTimeUnit enum('D','Y','M','H') DEFAULT 'D',
Content TEXT NULL,
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
SwalTitle VARCHAR(255) DEFAULT 'Terms of Use',

Content TEXT NULL,
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
HeaderButton enum('Y','N') DEFAULT 'Y',
HeaderButtonText VARCHAR(255) DEFAULT 'Terms Of Use',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
HeaderButtonText VARCHAR(255) DEFAULT 'Terms Of Use',
HeaderButtonText VARCHAR(255) DEFAULT 'Terms of Use',

PolicyRenewalTime INT DEFAULT 7, -- Number of days before the policy is renewed
PolicyRenewalTimeUnit enum('D','Y','M','H') DEFAULT 'D', -- Unit of the renewal time
Content TEXT NULL,
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
SwalTitle VARCHAR(255) DEFAULT 'Terms of Use',

Content TEXT NULL,
SwalTitle VARCHAR(255) DEFAULT 'Terms Of Use',
HeaderButton enum('Y','N') DEFAULT 'Y',
HeaderButtonText VARCHAR(255) DEFAULT 'Terms Of Use',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
HeaderButtonText VARCHAR(255) DEFAULT 'Terms Of Use',
HeaderButtonText VARCHAR(255) DEFAULT 'Terms of Use',

HeaderButton enum('Y','N') DEFAULT 'Y',
HeaderButtonText VARCHAR(255) DEFAULT 'Terms Of Use',
Active enum('Y','N') DEFAULT 'Y',
AcceptButton enum('Y','N') DEFAULT 'Y',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
AcceptButton enum('Y','N') DEFAULT 'Y',

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE `policies`;
LOCK TABLES `policies` WRITE;
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (1,'dataquery_example','v1',49,7,'D','By using this Data Query Tool, you acknowledge that you know it is in beta and may not work as expected. You also agree to use it responsibly and not to misuse the data.','Terms Of Use','Y','Terms Of Use','Y','Yes, I accept','Decline','2025-05-28 10:54:21','2025-05-28 10:54:21');
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (1,'dataquery_example','v1',49,7,'D','By using this Data Query Tool, you acknowledge that you know it is in beta and may not work as expected. You also agree to use it responsibly and not to misuse the data.','Terms Of Use','Y','Terms Of Use','Y','Yes, I accept','Decline','2025-05-28 10:54:21','2025-05-28 10:54:21');
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (1,'dataquery_example','v1',49,7,'D','By using this Data Query Tool, you acknowledge that you know it is in beta and may not work as expected. You also agree to use it responsibly and not to misuse the data.','Terms of Use','Y','Terms of Use','Y','Yes, I accept','Decline','2025-05-28 10:54:21','2025-05-28 10:54:21');

TRUNCATE TABLE `policies`;
LOCK TABLES `policies` WRITE;
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (1,'dataquery_example','v1',49,7,'D','By using this Data Query Tool, you acknowledge that you know it is in beta and may not work as expected. You also agree to use it responsibly and not to misuse the data.','Terms Of Use','Y','Terms Of Use','Y','Yes, I accept','Decline','2025-05-28 10:54:21','2025-05-28 10:54:21');
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (2,'login_example','v1',28,7,'D','By using this LORIS instance you acknowledge that you know it is filled with test data, and not real user data.','Terms Of Use','Y','Terms Of Use','Y','Accept','','2025-05-28 10:54:23','2025-05-28 10:54:23');
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (2,'login_example','v1',28,7,'D','By using this LORIS instance you acknowledge that you know it is filled with test data, and not real user data.','Terms Of Use','Y','Terms Of Use','Y','Accept','','2025-05-28 10:54:23','2025-05-28 10:54:23');
INSERT INTO `policies` (`PolicyID`, `Name`, `Version`, `ModuleID`, `PolicyRenewalTime`, `PolicyRenewalTimeUnit`, `Content`, `SwalTitle`, `HeaderButton`, `HeaderButtonText`, `Active`, `AcceptButtonText`, `DeclineButtonText`, `CreatedAt`, `UpdatedAt`) VALUES (2,'login_example','v1',28,7,'D','By using this LORIS instance you acknowledge that you know it is filled with test data, and not real user data.','Terms of Use','Y','Terms of Use','Y','Accept','','2025-05-28 10:54:23','2025-05-28 10:54:23');

Version VARCHAR(50) NOT NULL,
ModuleID INT NOT NULL,
PolicyRenewalTime INT DEFAULT 7,
PolicyRenewalTimeUnit enum('D','Y','M','H') DEFAULT 'D',
Copy link
Contributor

Choose a reason for hiding this comment

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

It's obvious what these are, but I personally think it's worth the splurge to write out the units

AND p.Active = 'Y'
AND p.HeaderButton IN $headerWhere
AND Version = (
SELECT MAX(Version)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this will always work as expected with Version VARCHAR(50)

Copy link
Contributor

Choose a reason for hiding this comment

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

Can also likely be shortened with: ORDER BY Version DESC LIMIT 1

AND DecisionDate = (
SELECT MAX(DecisionDate)
FROM user_policy_decision
WHERE
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is equivalent to ORDER BY DecisionDate DESC LIMIT 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Language: Javascript PR or issue that update Javascript code Language: PHP PR or issue that update PHP code Language: SQL PR or issue that update SQL code Module: login PR or issue related to login module Project: CCNA Issue or PR related to the CCNA project Project: EEGNet Issue or PR related to the EEGNet project RaisinBread PR or issue introducing/requiring improvements to the Raidinbread dataset
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants