Skip to content

Commit

Permalink
add: Provide a “terms of service” mecanism
Browse files Browse the repository at this point in the history
  • Loading branch information
marienfressinaud committed Oct 2, 2020
1 parent 9e73679 commit 2d1395b
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
!/cache/.keep
/data/*
!/data/.keep
/policies/*
!/policies/.keep

/public/dev_assets
6 changes: 6 additions & 0 deletions docs/production.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ distinguish your instance from the other ones. This is pretty simple: uncomment
the `APP_BRAND` variable in your `.env` file, and set the name of your choice.
It’s recommended to choose a short name.

## Bonus: Add terms of service

If your instance is opened, you may want to ask your users to accept the terms
of your service. For this, you must create the `policies/terms.html` file which
only accepts HTML. A checkbox should be added on the registration form then.

## Bonus: Close the registrations

You might want to setup a private instance of flusio. The registrations can be
Expand Down
Binary file modified locales/fr_FR/LC_MESSAGES/main.mo
Binary file not shown.
42 changes: 34 additions & 8 deletions locales/fr_FR/LC_MESSAGES/main.po
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: flusio\n"
"POT-Creation-Date: 2020-10-01 14:02+0200\n"
"PO-Revision-Date: 2020-10-01 14:03+0200\n"
"POT-Creation-Date: 2020-10-02 10:46+0200\n"
"PO-Revision-Date: 2020-10-02 10:48+0200\n"
"Last-Translator: Marien Fressinaud <[email protected]>\n"
"Language-Team: \n"
"Language: fr_FR\n"
Expand All @@ -18,7 +18,7 @@ msgstr ""
#: Accounts.php:83 Accounts.php:180 Collections.php:122 Collections.php:315
#: Collections.php:506 Collections.php:559 LinkMessages.php:70 Links.php:179
#: Links.php:322 NewsLinks.php:119 NewsLinks.php:268 NewsLinks.php:359
#: Registrations.php:84 Registrations.php:252 Sessions.php:82
#: Registrations.php:95 Registrations.php:277 Sessions.php:82
msgid "A security verification failed: you should retry to submit the form."
msgstr ""
"Une vérification de sécurité a échoué : vous devriez essayer de resoumettre "
Expand Down Expand Up @@ -76,15 +76,19 @@ msgstr "Le lien doit être associé à une collection."
msgid "“%s”"
msgstr "« %s »"

#: Registrations.php:107
#: Registrations.php:120
msgid "An account already exists with this email address."
msgstr "Un compte existe déjà avec cette adresse courriel."

#: Registrations.php:186 Registrations.php:200
#: Registrations.php:132
msgid "You must accept the terms of service."
msgstr "Vous devez accepter les conditions générales d’utilisation"

#: Registrations.php:211 Registrations.php:225
msgid "The token doesn’t exist."
msgstr "Le token n’existe pas."

#: Registrations.php:193
#: Registrations.php:218
msgid "The token has expired or has been invalidated."
msgstr "Le token a expiré ou a été invalidé."

Expand Down Expand Up @@ -346,7 +350,7 @@ msgid "Oh no&nbsp;😟"
msgstr "Oh non&nbsp;😟"

#: views/_layouts/not_connected.phtml:62 views/registrations/new.phtml:3
#: views/registrations/new.phtml:9 views/registrations/new.phtml:109
#: views/registrations/new.phtml:9 views/registrations/new.phtml:134
msgid "Sign up"
msgstr "S’inscrire"

Expand Down Expand Up @@ -1192,6 +1196,14 @@ msgstr "système de design de flusio"
msgid "Colors"
msgstr "Couleurs"

#: views/pages/terms.phtml:3 views/pages/terms.phtml:9
msgid "Terms of service"
msgstr "Conditions générales d’utilisation"

#: views/pages/terms.phtml:16
msgid "back to the registration"
msgstr "retour à l’inscription"

#: views/registrations/new.phtml:23
msgid "How should we name you?"
msgstr "Comment devons-nous vous appeler ?"
Expand All @@ -1212,7 +1224,21 @@ msgstr "Et un mot de passe"
msgid "A strong password is at least 8 characters long."
msgstr "Un mot de passe robuste fait au moins 8 caractères."

#: views/registrations/new.phtml:113
#: views/registrations/new.phtml:110
#, php-format
msgid ""
"Before going any further, you should read <a href=\"%s\" target=\"_blank"
"\">the terms of service</a> to make sure they are suitable for you."
msgstr ""
"Avant d’aller plus loin, vous devriez prendre le temps de lire <a href=\"%s"
"\" target=\"_blank\">les conditions générales d’utilisation</a> pour vous "
"assurer que celles-ci vous conviennent."

#: views/registrations/new.phtml:121
msgid "Accept the terms of service"
msgstr "Accepter les conditions générales d’utilisation"

#: views/registrations/new.phtml:138
msgid "Already an account? Sign in"
msgstr "Déjà un compte ? Se connecter"

Expand Down
Empty file added policies/.keep
Empty file.
1 change: 1 addition & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public function __construct()
// Initialize the routes
$router = new \Minz\Router();
$router->addRoute('get', '/', 'Pages#home', 'home');
$router->addRoute('get', '/terms', 'Pages#terms', 'terms');

// Registration
$router->addRoute('get', '/registration', 'Registrations#new', 'registration');
Expand Down
24 changes: 24 additions & 0 deletions src/Pages.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ public function home()
}
}

/**
* Show the terms of service.
*
* @response 404
* if the policies/legals.html file doesn’t exist
* @response 200
* on success
*
* @return \Minz\Response
*/
public function terms()
{
$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
$terms = @file_get_contents($terms_path);
if (!$terms) {
return Response::notFound('not_found.phtml');
}

return Response::ok('pages/terms.phtml', [
'terms' => $terms,
]);
}

/**
* Show the design page.
*
Expand Down
25 changes: 25 additions & 0 deletions src/Registrations.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ public function new()
return Response::redirect('login');
}

$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
$has_terms = file_exists($terms_path);

return Response::ok('registrations/new.phtml', [
'has_terms' => $has_terms,
'username' => '',
'email' => '',
'password' => '',
Expand Down Expand Up @@ -67,9 +72,14 @@ public function create($request)
return Response::redirect('login');
}

$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
$has_terms = file_exists($terms_path);

$username = $request->param('username');
$email = $request->param('email');
$password = $request->param('password');
$accept_terms = $request->param('accept_terms', false);
$user_dao = new models\dao\User();
$collection_dao = new models\dao\Collection();
$token_dao = new models\dao\Token();
Expand All @@ -78,6 +88,7 @@ public function create($request)

if (!$csrf->validateToken($request->param('csrf'))) {
return Response::badRequest('registrations/new.phtml', [
'has_terms' => $has_terms,
'username' => $username,
'email' => $email,
'password' => $password,
Expand All @@ -91,6 +102,7 @@ public function create($request)
$errors = $user->validate();
if ($errors) {
return Response::badRequest('registrations/new.phtml', [
'has_terms' => $has_terms,
'username' => $username,
'email' => $email,
'password' => $password,
Expand All @@ -100,6 +112,7 @@ public function create($request)

if ($user_dao->findBy(['email' => $user->email])) {
return Response::badRequest('registrations/new.phtml', [
'has_terms' => $has_terms,
'username' => $username,
'email' => $email,
'password' => $password,
Expand All @@ -109,6 +122,18 @@ public function create($request)
]);
}

if ($has_terms && !$accept_terms) {
return Response::badRequest('registrations/new.phtml', [
'has_terms' => $has_terms,
'username' => $username,
'email' => $email,
'password' => $password,
'errors' => [
'accept_terms' => _('You must accept the terms of service.'),
],
]);
}

$validation_token = models\Token::init(1, 'day', 8);
$token_dao->save($validation_token);

Expand Down
11 changes: 11 additions & 0 deletions src/assets/stylesheets/_forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,14 @@ legend {
border: var(--border-width) solid var(--border-error-color);
border-radius: var(--border-radius);
}

.form-group--terms {
padding: var(--space-medium);

background-color: var(--color-purple-1);
border-radius: var(--border-radius);
}

.form-group--terms .form-group__caption {
margin-top: 0;
}
19 changes: 19 additions & 0 deletions src/views/pages/terms.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
$this->layout('base.phtml', [
'title' => _('Terms of service'),
]);
?>

<div class="section section--small">
<div class="section__title">
<h1><?= _('Terms of service') ?></h1>
</div>

<?= $this->safe('terms') ?>

<p class="paragraph--centered">
<a class="anchor--action" href="<?= url('registration') ?>">
<?= _('back to the registration') ?>
</a>
</p>
</div>
25 changes: 25 additions & 0 deletions src/views/registrations/new.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,31 @@
<?php endif; ?>
</div>

<?php if ($has_terms): ?>
<div class="form-group form-group--terms <?= isset($errors['accept_terms']) ? 'form-group--invalid' : '' ?>">
<p class="form-group__caption">
<?= _f('Before going any further, you should read <a href="%s" target="_blank">the terms of service</a> to make sure they are suitable for you.', url('terms')) ?>
</p>

<input
type="checkbox"
id="accept-terms"
name="accept_terms"
required
/>

<label class="label--checkbox" for="accept-terms">
<?= _('Accept the terms of service') ?>
</label>

<?php if (isset($errors['accept_terms'])): ?>
<p class="form-group__error">
<?= $errors['accept_terms'] ?>
</p>
<?php endif; ?>
</div>
<?php endif; ?>

<div class="form__actions">
<button type="submit" class="button--primary">
<?= _('Sign up') ?>
Expand Down
24 changes: 24 additions & 0 deletions tests/PagesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
class PagesTest extends \PHPUnit\Framework\TestCase
{
use \tests\LoginHelper;
use \tests\FakerHelper;
use \Minz\Tests\InitializerHelper;
use \Minz\Tests\ApplicationHelper;
use \Minz\Tests\ResponseAsserts;
Expand All @@ -25,6 +26,29 @@ public function testHomeRedirectsToNewsIfConnected()
$this->assertResponse($response, 302, '/news');
}

public function testTermsRendersCorrectlyWhenTermsExist()
{
$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
file_put_contents($terms_path, $this->fake('sentence'));

$response = $this->appRun('GET', '/terms');

@unlink($terms_path);
$this->assertResponse($response, 200, 'Terms of service');
}

public function testTermsFailsIfTermsDoNotExist()
{
$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
@unlink($terms_path);

$response = $this->appRun('GET', '/terms');

$this->assertResponse($response, 404);
}

public function testDesignRendersCorrectly()
{
$response = $this->appRun('GET', '/design');
Expand Down
40 changes: 40 additions & 0 deletions tests/RegistrationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,26 @@ public function testCreateReturnsACookie()
$this->assertSame($db_session['token'], $cookie['value']);
}

public function testCreateTakesAcceptTermsIfExist()
{
$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
file_put_contents($terms_path, $this->fake('sentence'));
$user_dao = new models\dao\User();

$response = $this->appRun('post', '/registration', [
'csrf' => (new \Minz\CSRF())->generateToken(),
'username' => $this->fake('name'),
'email' => $this->fake('email'),
'password' => $this->fake('password'),
'accept_terms' => true,
]);

@unlink($terms_path);
$this->assertSame(1, $user_dao->count());
$this->assertResponse($response, 302, '/onboarding');
}

public function testCreateRedirectsToHomeIfConnected()
{
$this->login();
Expand Down Expand Up @@ -308,6 +328,26 @@ public function testCreateFailsIfPasswordIsMissing()
$this->assertResponse($response, 400, 'The password is required');
}

public function testCreateFailsIfAcceptTermsIsFalseAndTermsExist()
{
$app_path = \Minz\Configuration::$app_path;
$terms_path = $app_path . '/policies/terms.html';
file_put_contents($terms_path, $this->fake('sentence'));
$user_dao = new models\dao\User();

$response = $this->appRun('post', '/registration', [
'csrf' => (new \Minz\CSRF())->generateToken(),
'username' => $this->fake('name'),
'email' => $this->fake('email'),
'password' => $this->fake('password'),
'accept_terms' => false,
]);

@unlink($terms_path);
$this->assertSame(0, $user_dao->count());
$this->assertResponse($response, 400, 'You must accept the terms of service');
}

public function testValidationWithoutTokenAndConnectedRendersCorrectly()
{
$expired_at = \Minz\Time::fromNow($this->fake('numberBetween', 1, 9000), 'minutes');
Expand Down

0 comments on commit 2d1395b

Please sign in to comment.