Skip to content
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

Add capability to add multiple request forms #734

Merged
merged 10 commits into from
Aug 8, 2022

Conversation

stwalkerster
Copy link
Member

Request forms are per-domain, and can be routed to specific queues.

Currently, the form fields cannot be changed, but all the text can be. Formatting is done via Markdown in a safe rendering mode to avoid any code injection, but to permit the usage of Bootstrap styling for things like alert boxes.

This also shows on the request zoom page where this request has come from, plus leaving a comment indicating why the request is in that queue:
image

Interesting things do happen if both a custom form and a defer-type ban are set:
image

Fixes #517 #604 #605

@stwalkerster
Copy link
Member Author

Deployed to https://accounts-dev.wmflabs.org/demo/internal.php if you want a play around with it

@dqwiki
Copy link
Member

dqwiki commented Apr 25, 2022

I'm worried about the potential conflict this will create with domain management. If we intend to deploy domain management how would these requests be sorted by domain?

@dqwiki dqwiki self-requested a review April 25, 2022 01:47
@stwalkerster
Copy link
Member Author

I'm worried about the potential conflict this will create with domain management. If we intend to deploy domain management how would these requests be sorted by domain?

So this is actually built primarily with domains in mind, allowing the creation form to be customised per-domain. Almost everything is (will be) split per-domain, including requests and request queues (though that split isn't enforced yet). A request queue is created in a specific domain, and will deposit requests in a domain-specific request queue. You will only see request queues from your current domain.

Base automatically changed from multiproject/domainreg to master August 5, 2022 15:51
Copy link
Member

@FastLizard4 FastLizard4 left a comment

Choose a reason for hiding this comment

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

My review so far, which consists of questions mostly just to satisfy my curiosity/help my understanding/memory of how all this works

/** @var string */
private $formcontent;
private $formcontent = '';
Copy link
Member

Choose a reason for hiding this comment

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

Out of curiosity, why these changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because PHP.

Actually, because the get*() methods in RequestForm are type-restricted to be a string, and PHP defaults variables to null. Since these are required fields, I don't really want to make them nullable (the string? type annotation)

For both creation and edits, PageRequestFormManagement calls the populateFromObject method to make it easier to set all the field assignments on the template, but for new objects it's done via populateFromObject(new RequestForm()), thus all the fields are default values, and (without this change) the fields are all null which doesn't match the type annotation on the get*() methods. For a recent example of this sort of thing happening in prod, see #754

public function isRequestFormTarget(RequestQueue $queue, PdoDatabase $database): bool
{
$isTarget = false;
$forms = RequestForm::getAllForms($database, 1); // FIXME: domains
Copy link
Member

Choose a reason for hiding this comment

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

What's this FIXME for?

Copy link
Member Author

Choose a reason for hiding this comment

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

In many places, I've hard-coded the domain ID 1 until everything supports retrieving via domain and we start actually enforcing domains on login sessions. These FIXMEs are the locations where the domain is hard-coded so it's much easier to find them later.

They will be fixed probably in #600, which is part of the multi-domain push (#532)

Comment on lines 194 to 196
if ($form->getDomain() !== Domain::getCurrent($database)->getId()) {
throw new AccessDeniedException();
}
Copy link
Member

Choose a reason for hiding this comment

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

I see both edit() and view() have a block like this; do preview() and create() need one too? Or do I just not remember how the access control checks work? 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

This check is to make sure the user's current domain is able to see this specific object. It's basically one of the checks I wanted to add in #600 (see your other comment about the FIXMEs).

Since this is a new object, create() doesn't need this check as the object will be created in the user's current domain (see L81).

Since preview never actually calls the database and just populates from what's in the user's session, there's no object to check against. The user must have been able to see an object (or create an object) already for this to work.


$this->setupObjectFromPost($form);

if (WebRequest::postString("preview") === "preview") {
Copy link
Member

Choose a reason for hiding this comment

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

Is this redundant with the preview() method?

Copy link
Member Author

Choose a reason for hiding this comment

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

If I remember this code correctly, preview() launches an iframe under the edit() mode. This fragment of code handles the refresh (submit!) of the edit() mode, and sets up the session variables to pass to the iframe. The preview() mode in the iframe then actually handles the render.

Not redundant, two parts of the same functionality.

add emailhelp text not null,
add commentshelp text not null;

INSERT INTO requestform (updateversion, enabled, domain, name, publicendpoint, formcontent, overridequeue, usernamehelp, emailhelp, commentshelp) VALUES (9, 1, 1, 'Default form', 'default', '## Request an account!
Copy link
Member

Choose a reason for hiding this comment

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

Out of curiosity, why updateversion of 9?

Copy link
Member Author

Choose a reason for hiding this comment

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

I actually have no idea what I was thinking four months ago!

I think what happened was I imported the existing template, made tweaks to it through the GUI to convert from HTML to markdown, and then exported the row as a SQL insert into the migration script, and it just happened to be version 9.

This makes no appreciable difference though, updateversion is an unsigned 32-bit integer so as long as we don't make over 4 billion(ish) changes to this request form, a difference of 9 isn't going to matter 😀

Also tweaks the updateversion of the sql script, not that it really
matters much.
Copy link
Member

@FastLizard4 FastLizard4 left a comment

Choose a reason for hiding this comment

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

Code looks good to me (though since it's been so long since reviewing ACC code I can't guarantee I haven't missed something subtle, like the exceptions missing constructor args). I did notice an issue during my testing, but given the nature of the multi-domain work I imagine it might very well be expected at this point. Let me know if it is and I'll approve!

If you create a fresh domain and request form within that domain, but don't specify a queue for that request form to go to (leaving it at "(Use default queue)"), you get an exception when trying to submit a request. The exception occurs at line 112 of PageRequestAccount.php:

$request->setQueue(RequestQueue::getDefaultQueue($database, $domain)->getId());

...Because getDefaultQueue() returns false, and you can't call getId() on a boolean. Note that I did create a queue for my new domain, but I didn't set it as the default for requests. Trying to set an explicit default queue for the form results in a "The chosen queue does not exist or is disabled" error message, seemingly because the created queue doesn't belong to the domain I created it in.

@stwalkerster
Copy link
Member Author

Yep, that's expected at the moment - many things don't work with domains yet - most of the work has been getting the tool to a point where the "make domains work" PR can be as small as possible. When you create several domains and try to use the second domain, things do break due to the hardcoding of domain id 1 almost everywhere

Copy link
Member

@FastLizard4 FastLizard4 left a comment

Choose a reason for hiding this comment

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

Makes sense. :shipit:!

@stwalkerster stwalkerster merged commit 138166e into master Aug 8, 2022
@stwalkerster stwalkerster deleted the multiproject/requestforms branch August 8, 2022 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
schema changes This task requires database schema changes
Projects
Status: Done
Archived in project
3 participants