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

Store motion list settings #818

Merged
merged 3 commits into from
Jul 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion History.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
- It can now be set up so that the modified version proposed as part of a proposed procedure is shown inline as part of the motion.
- Besides of exporting all motions as a ZIP-file containing single ODT files, a single ODT file containing all motion texts can now be exported.
- The ODT export now also supports numbered lists.
- The motion list can now be filtered for To Do items (that is, motions/amendments that need to be screened).
- The motion list can now be filtered for To Do items (that is, motions/amendments that need to be screened) and also shows the To Do action for items on that list as part of the Status.
- The motion list now persists its filter and sort settings for each user session, until changed or reset.
- Bugfix: Some edge cases around uploaded logos breaking the PDF export or not being shown on the page were resolved.
- Bugfix: Super-admins could lock themselves out of protected consultations.

Expand Down
Binary file modified assets/OpenOffice-Template-Std.odt
Binary file not shown.
3 changes: 3 additions & 0 deletions assets/OpenOffice-Template-odt/content.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
<text:p text:style-name="Frame_20_contents">
<text:span text:style-name="T1">{{ANTRAGSGRUEN:INITIATORS}}</text:span>
</text:p>
<text:p text:style-name="Frame_20_contents">
<text:span text:style-name="T1">{{ANTRAGSGRUEN:STATUS}}</text:span>
</text:p>
</draw:text-box>
</draw:frame>
</text:p>
Expand Down
61 changes: 33 additions & 28 deletions controllers/AmendmentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -453,9 +453,10 @@ public function actionSaveProposalStatus(string $motionSlug, int $amendmentId):
if (!$amendment) {
return new RestApiExceptionResponse(404, 'Amendment not found');
}
if (!$amendment->canEditProposedProcedure()) {
if (!$amendment->canEditLimitedProposedProcedure()) {
return new RestApiExceptionResponse(403, 'Not permitted to change the status');
}
$canChangeProposalUnlimitedly = $amendment->canEditProposedProcedure();

$response = [];
$msgAlert = null;
Expand All @@ -467,18 +468,20 @@ public function actionSaveProposalStatus(string $motionSlug, int $amendmentId):
$amendment = $plugin::onBeforeProposedProcedureStatusSave($amendment);
}

$setStatus = intval($this->getHttpRequest()->post('setStatus'));
if ($amendment->proposalStatus !== $setStatus) {
$ppChanges->setProposalStatusChanges($amendment->proposalStatus, $setStatus);
if ($amendment->proposalUserStatus !== null) {
$msgAlert = \Yii::t('amend', 'proposal_user_change_reset');
if ($canChangeProposalUnlimitedly) {
$setStatus = intval($this->getHttpRequest()->post('setStatus'));
if ($amendment->proposalStatus !== $setStatus) {
$ppChanges->setProposalStatusChanges($amendment->proposalStatus, $setStatus);
if ($amendment->proposalUserStatus !== null) {
$msgAlert = \Yii::t('amend', 'proposal_user_change_reset');
}
$amendment->proposalUserStatus = null;
}
$amendment->proposalUserStatus = null;
}
$amendment->proposalStatus = $setStatus;
$amendment->proposalStatus = $setStatus;

$ppChanges->setProposalCommentChanges($amendment->proposalComment, $this->getHttpRequest()->post('proposalComment', ''));
$amendment->proposalComment = $this->getHttpRequest()->post('proposalComment', '');
$ppChanges->setProposalCommentChanges($amendment->proposalComment, $this->getHttpRequest()->post('proposalComment', ''));
$amendment->proposalComment = $this->getHttpRequest()->post('proposalComment', '');
}

$oldTags = $amendment->getProposedProcedureTags();
$newTags = [];
Expand All @@ -501,26 +504,28 @@ public function actionSaveProposalStatus(string $motionSlug, int $amendmentId):
$ppChanges->setProposalTagsHaveChanged(array_keys($oldTags), $newTags);
}

$proposalExplanationPre = $amendment->proposalExplanation;
if ($this->getHttpRequest()->post('proposalExplanation', null) !== null) {
if (trim($this->getHttpRequest()->post('proposalExplanation', '')) === '') {
$amendment->proposalExplanation = null;
if ($canChangeProposalUnlimitedly) {
$proposalExplanationPre = $amendment->proposalExplanation;
if ($this->getHttpRequest()->post('proposalExplanation', null) !== null) {
if (trim($this->getHttpRequest()->post('proposalExplanation', '')) === '') {
$amendment->proposalExplanation = null;
} else {
$amendment->proposalExplanation = $this->getHttpRequest()->post('proposalExplanation', '');
}
} else {
$amendment->proposalExplanation = $this->getHttpRequest()->post('proposalExplanation', '');
$amendment->proposalExplanation = null;
}
} else {
$amendment->proposalExplanation = null;
}
$ppChanges->setProposalExplanationChanges($proposalExplanationPre, $amendment->proposalExplanation);
$ppChanges->setProposalExplanationChanges($proposalExplanationPre, $amendment->proposalExplanation);

if ($this->getHttpRequest()->post('visible', 0)) {
if ($amendment->proposalVisibleFrom === null) {
// Reload the page, to update section titles and permissions to edit the proposed procedure
$response['redirectToUrl'] = UrlHelper::createAmendmentUrl($amendment, 'view');
if ($this->getHttpRequest()->post('visible', 0)) {
if ($amendment->proposalVisibleFrom === null) {
// Reload the page, to update section titles and permissions to edit the proposed procedure
$response['redirectToUrl'] = UrlHelper::createAmendmentUrl($amendment, 'view');
}
$amendment->setProposalPublished();
} else {
$amendment->proposalVisibleFrom = null;
}
$amendment->setProposalPublished();
} else {
$amendment->proposalVisibleFrom = null;
}

try {
Expand Down Expand Up @@ -628,7 +633,7 @@ public function actionEditProposedChange(string $motionSlug, int $amendmentId):
if (!$amendment) {
return new HtmlErrorResponse(404, 'Amendment not found');
}
if (!User::havePrivilege($this->consultation, Privileges::PRIVILEGE_CHANGE_PROPOSALS, PrivilegeQueryContext::amendment($amendment))) {
if (!$amendment->canEditProposedProcedure()) {
return new HtmlErrorResponse(403, 'Not permitted to change the proposed procedure');
}

Expand Down
61 changes: 33 additions & 28 deletions controllers/MotionActionsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -459,9 +459,10 @@ public function actionSaveProposalStatus(string $motionSlug): ResponseInterface
if (!$motion) {
return new RestApiExceptionResponse(404, 'Motion not found');
}
if (!$motion->canEditProposedProcedure()) {
if (!$motion->canEditLimitedProposedProcedure()) {
return new RestApiExceptionResponse(403, 'Not permitted to change the status');
}
$canChangeProposalUnlimitedly = $motion->canEditProposedProcedure();

$response = [];
$msgAlert = null;
Expand All @@ -474,18 +475,20 @@ public function actionSaveProposalStatus(string $motionSlug): ResponseInterface
$motion = $plugin::onBeforeProposedProcedureStatusSave($motion);
}

$setStatus = intval($this->getHttpRequest()->post('setStatus'));
if ($motion->proposalStatus !== $setStatus) {
$ppChanges->setProposalStatusChanges($motion->proposalStatus, $setStatus);
if ($motion->proposalUserStatus !== null) {
$msgAlert = \Yii::t('amend', 'proposal_user_change_reset');
if ($canChangeProposalUnlimitedly) {
$setStatus = intval($this->getHttpRequest()->post('setStatus'));
if ($motion->proposalStatus !== $setStatus) {
$ppChanges->setProposalStatusChanges($motion->proposalStatus, $setStatus);
if ($motion->proposalUserStatus !== null) {
$msgAlert = \Yii::t('amend', 'proposal_user_change_reset');
}
$motion->proposalUserStatus = null;
}
$motion->proposalUserStatus = null;
}
$motion->proposalStatus = $setStatus;
$motion->proposalStatus = $setStatus;

$ppChanges->setProposalCommentChanges($motion->proposalComment, $this->getHttpRequest()->post('proposalComment', ''));
$motion->proposalComment = $this->getHttpRequest()->post('proposalComment', '');
$ppChanges->setProposalCommentChanges($motion->proposalComment, $this->getHttpRequest()->post('proposalComment', ''));
$motion->proposalComment = $this->getHttpRequest()->post('proposalComment', '');
}

$oldTags = $motion->getProposedProcedureTags();
$newTags = [];
Expand All @@ -508,26 +511,28 @@ public function actionSaveProposalStatus(string $motionSlug): ResponseInterface
$ppChanges->setProposalTagsHaveChanged(array_keys($oldTags), $newTags);
}

$proposalExplanationPre = $motion->proposalExplanation;
if ($this->getHttpRequest()->post('proposalExplanation', null) !== null) {
if (trim($this->getHttpRequest()->post('proposalExplanation', '')) === '') {
$motion->proposalExplanation = null;
if ($canChangeProposalUnlimitedly) {
$proposalExplanationPre = $motion->proposalExplanation;
if ($this->getHttpRequest()->post('proposalExplanation', null) !== null) {
if (trim($this->getHttpRequest()->post('proposalExplanation', '')) === '') {
$motion->proposalExplanation = null;
} else {
$motion->proposalExplanation = $this->getHttpRequest()->post('proposalExplanation', '');
}
} else {
$motion->proposalExplanation = $this->getHttpRequest()->post('proposalExplanation', '');
$motion->proposalExplanation = null;
}
} else {
$motion->proposalExplanation = null;
}
$ppChanges->setProposalExplanationChanges($proposalExplanationPre, $motion->proposalExplanation);
$ppChanges->setProposalExplanationChanges($proposalExplanationPre, $motion->proposalExplanation);

if ($this->getHttpRequest()->post('visible', 0)) {
if ($motion->proposalVisibleFrom === null) {
// Reload the page, to update section titles and permissions to edit the proposed procedure
$response['redirectToUrl'] = UrlHelper::createMotionUrl($motion, 'view');
if ($this->getHttpRequest()->post('visible', 0)) {
if ($motion->proposalVisibleFrom === null) {
// Reload the page, to update section titles and permissions to edit the proposed procedure
$response['redirectToUrl'] = UrlHelper::createMotionUrl($motion, 'view');
}
$motion->setProposalPublished();
} else {
$motion->proposalVisibleFrom = null;
}
$motion->setProposalPublished();
} else {
$motion->proposalVisibleFrom = null;
}

try {
Expand Down Expand Up @@ -630,7 +635,7 @@ public function actionEditProposedChange(string $motionSlug): ResponseInterface
if (!$motion) {
return new HtmlErrorResponse(404, 'Motion not found');
}
if (!User::havePrivilege($this->consultation, Privileges::PRIVILEGE_CHANGE_PROPOSALS, PrivilegeQueryContext::motion($motion))) {
if (!$motion->canEditProposedProcedure()) {
return new HtmlErrorResponse(403, 'Not permitted to edit the proposed procedure');
}

Expand Down
16 changes: 12 additions & 4 deletions controllers/admin/MotionListController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
namespace app\controllers\admin;

use app\models\exceptions\{Access, NotFound, ExceptionBase, ResponseException};
use app\components\{Tools, ZipWriter};
use app\components\{RequestContext, Tools, UrlHelper, ZipWriter};
use app\models\db\{Amendment, Consultation, IMotion, Motion, User};
use app\models\forms\AdminMotionFilterForm;
use app\models\http\{BinaryFileResponse, HtmlErrorResponse, HtmlResponse, ResponseInterface};
use app\models\http\{BinaryFileResponse, HtmlErrorResponse, HtmlResponse, RedirectResponse, ResponseInterface};
use app\models\settings\{AntragsgruenApp, PrivilegeQueryContext, Privileges};
use app\views\amendment\LayoutHelper as AmendmentLayoutHelper;
use app\views\motion\LayoutHelper as MotionLayoutHelper;
Expand Down Expand Up @@ -248,8 +248,16 @@ public function actionIndex(?string $motionId = null): ResponseInterface

/** @var AdminMotionFilterForm $search */
$search = new $motionListClass($consultation, $motions, $privilegeScreening);
if ($this->isRequestSet('Search')) {
$search->setAttributes($this->getRequestValue('Search'));
if ($this->isRequestSet('reset')) {
RequestContext::getSession()->set('motionListSearch', null);
return new RedirectResponse(UrlHelper::createUrl('/admin/motion-list/index'));
}
if ($this->getRequestValue('Search')) {
$attributes = $this->getRequestValue('Search');
RequestContext::getSession()->set('motionListSearch', $attributes);
$search->setAttributes($attributes);
} elseif (RequestContext::getSession()->get('motionListSearch')) {
$search->setAttributes(RequestContext::getSession()->get('motionListSearch'));
}

return new HtmlResponse($this->render('list_all', [
Expand Down
1 change: 1 addition & 0 deletions messages/de/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
'list_motion_short' => 'A',
'list_amend_short' => 'ÄA',
'list_search_do' => 'Suchen',
'list_search_reset' => 'Zurücksetzen',
'list_delete' => 'Löschen',
'list_unscreen' => 'Ent-Freischalten',
'list_screen' => 'Freischalten',
Expand Down
1 change: 1 addition & 0 deletions messages/de/export.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'tags' => 'Themen',
'contact' => 'Kontakt',
'procedure' => 'Verfahren',
'proposed_procedure' => 'Verfahrensvorschlag',
'comments' => 'Kommentare',
'mail_motion_x' => 'Antrags %MOTION%',
'mail_amendment_x_to_y' => 'Änderungsantrags %AMENDMENT% zum Antrag %MOTION%',
Expand Down
1 change: 1 addition & 0 deletions messages/en/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
'list_motion_short' => 'A',
'list_amend_short' => 'ÄA',
'list_search_do' => 'Search',
'list_search_reset' => 'Reset',
'list_delete' => 'Delete',
'list_unscreen' => 'Unscreen',
'list_screen' => 'Screen',
Expand Down
1 change: 1 addition & 0 deletions messages/en/export.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'tags' => 'Tags',
'contact' => 'Contact',
'procedure' => 'Procedure',
'proposed_procedure' => 'Proposed procedure',
'comments' => 'Comments',
'mail_motion_x' => 'motion %MOTION%',
'mail_amendment_x_to_y' => 'amendment %AMENDMENT% to the motion %MOTION%',
Expand Down
28 changes: 18 additions & 10 deletions models/db/IMotion.php
Original file line number Diff line number Diff line change
Expand Up @@ -501,19 +501,27 @@ abstract public function hasAlternativeProposaltext(bool $includeOtherAmendments

abstract public function canSeeProposedProcedure(?string $procedureToken): bool;

/**
* Hint: "Limited" refers to functionality that comes after setting the actual proposed procedure,
* i.e., internal comments, voting blocks and communication with the proposer
*/
public function canEditLimitedProposedProcedure(): bool
{
return User::havePrivilege($this->getMyConsultation(), Privileges::PRIVILEGE_CHANGE_PROPOSALS, PrivilegeQueryContext::imotion($this)) ||
User::havePrivilege($this->getMyConsultation(), Privileges::PRIVILEGE_CONSULTATION_SETTINGS, null);
}

public function canEditProposedProcedure(): bool
{
$consultation = $this->getMyConsultation();
$havePpRights = User::havePrivilege($consultation, Privileges::PRIVILEGE_CHANGE_PROPOSALS, PrivilegeQueryContext::imotion($this));
if ($consultation->getSettings()->ppEditableAfterPublication) {
return $havePpRights;
if (!$this->canEditLimitedProposedProcedure()) {
return false;
}

if ($this->isProposalPublic()) {
return $this->getMyConsultation()->getSettings()->ppEditableAfterPublication ||
User::havePrivilege($this->getMyConsultation(), Privileges::PRIVILEGE_CONSULTATION_SETTINGS, null);
} else {
if ($this->proposalVisibleFrom === null) {
return $havePpRights;
} else {
// If the proposal is published already, then only consultation admins can edit the proposal
return User::havePrivilege($consultation, Privileges::PRIVILEGE_CONSULTATION_SETTINGS, null);
}
return true;
}
}

Expand Down
Loading