mirror of
https://github.com/wassname/talk.git
synced 2026-07-13 02:44:50 +08:00
itterated on copy
This commit is contained in:
+3
-1
@@ -20,11 +20,13 @@ en:
|
||||
bio_offensive: "This bio is offensive"
|
||||
cancel: "Cancel"
|
||||
confirm_email:
|
||||
click_to_confirm: "Click below to confirm your email address"
|
||||
email_confirmation: "Email Confirmation"
|
||||
click_to_confirm: "Click below to confirm your email address."
|
||||
confirm: "Confirm"
|
||||
password_reset:
|
||||
mail_sent: 'If you have a registered account, a password reset link was sent to that email'
|
||||
set_new_password: "Change Your Password"
|
||||
change_password_help: "Please enter a new password to use to login. Make it secure!"
|
||||
new_password: "New Password"
|
||||
new_password_help: "Password must be at least 8 characters"
|
||||
confirm_new_password: "Confirm New Password"
|
||||
|
||||
@@ -1 +1 @@
|
||||
<p><%= t('email.download.download_link_ready') %> <a href="<%= BASE_URL %>account/download#<%= token %>"><%= t('email.download.download_archive') %></a></p>
|
||||
<p><%= t('email.download.download_link_ready', organizationName, now.toLocaleString()) %> <a href="<%= BASE_URL %>account/download#<%= token %>"><%= t('email.download.download_archive') %></a></p>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= t('email.download.download_link_ready') %>
|
||||
<%= t('email.download.download_link_ready', organizationName, now.toLocaleString()) %>
|
||||
|
||||
<%= BASE_URL %>account/download#<%= token %>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const { TalkError } = require('errors');
|
||||
|
||||
// ErrDownloadToken is returned in the event that the download is requested
|
||||
// without a valid token.
|
||||
class ErrDownloadToken extends TalkError {
|
||||
constructor(err) {
|
||||
super(
|
||||
'Token is invalid',
|
||||
{
|
||||
translation_key: 'DOWNLOAD_TOKEN_INVALID',
|
||||
status: 400,
|
||||
},
|
||||
{ err }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { ErrDownloadToken };
|
||||
@@ -4,6 +4,7 @@ const { DOWNLOAD_LINK_SUBJECT } = require('./constants');
|
||||
|
||||
async function sendDownloadLink({
|
||||
user,
|
||||
loaders: { Settings },
|
||||
connectors: {
|
||||
errors,
|
||||
secrets,
|
||||
@@ -43,19 +44,25 @@ async function sendDownloadLink({
|
||||
{ jwtid: uuid.v4(), expiresIn: '1d', subject: DOWNLOAD_LINK_SUBJECT }
|
||||
);
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const { organizationName } = await Settings.load('organizationName');
|
||||
|
||||
// Send the download link via the user's attached email account.
|
||||
await Users.sendEmail(user, {
|
||||
template: 'download',
|
||||
locals: {
|
||||
token,
|
||||
organizationName,
|
||||
now,
|
||||
},
|
||||
subject: I18n.t('email.download.subject'),
|
||||
subject: I18n.t('email.download.subject', organizationName),
|
||||
});
|
||||
|
||||
// Amend the lastAccountDownload on the user.
|
||||
await User.update(
|
||||
{ id: user.id },
|
||||
{ $set: { 'metadata.lastAccountDownload': new Date() } }
|
||||
{ $set: { 'metadata.lastAccountDownload': now } }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ const { get, pick, kebabCase } = require('lodash');
|
||||
const moment = require('moment');
|
||||
const archiver = require('archiver');
|
||||
const stringify = require('csv-stringify');
|
||||
const { ErrDownloadToken } = require('./errors');
|
||||
|
||||
async function verifyDownloadToken(
|
||||
{ connectors: { services: { Users } } },
|
||||
@@ -109,10 +110,7 @@ module.exports = router => {
|
||||
// Verify the token
|
||||
await verifyDownloadToken(req.context, token);
|
||||
} catch (err) {
|
||||
// Log out the error, slurp it and send out the predefined error to the
|
||||
// error handler.
|
||||
console.error(err);
|
||||
return next(new Error('invalid token'));
|
||||
return next(new ErrDownloadToken(err));
|
||||
}
|
||||
|
||||
res.status(204).end();
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
<title><%= t('download_landing.download_your_account') %></title>
|
||||
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
|
||||
<link rel="stylesheet" href="<%= BASE_PATH %>public/css/admin.css">
|
||||
<%- include(root + '/partials/head') %>
|
||||
<%- include(root + '/partials/account') %>
|
||||
</head>
|
||||
<body class="confirm-email-page">
|
||||
<body>
|
||||
<div id="root">
|
||||
<div class="error-console container"></div>
|
||||
<form id="download-form" class="container" method="post" action="<%= BASE_PATH %>api/v1/account/download">
|
||||
<legend class="legend"><%= t('download_landing.click_to_download') %></legend>
|
||||
<button type="submit"><%= t('download_landing.confirm') %></button>
|
||||
</form>
|
||||
<section class="container">
|
||||
<h1><%= t('download_landing.download_your_account') %></h1>
|
||||
<p><%= t('download_landing.download_details') %></p>
|
||||
<p><%= t('download_landing.all_information_included') %></p>
|
||||
<ul class="check_list">
|
||||
<li><%= t('download_landing.information_included.date') %></li>
|
||||
<li><%= t('download_landing.information_included.url') %></li>
|
||||
<li><%= t('download_landing.information_included.body') %></li>
|
||||
<li><%= t('download_landing.information_included.asset_url') %></li>
|
||||
</ul>
|
||||
<div class="error-console"></div>
|
||||
<form id="download-form" method="post" action="<%= BASE_PATH %>api/v1/account/download">
|
||||
<button type="submit"><%= t('download_landing.confirm') %></button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
@@ -21,9 +28,9 @@
|
||||
function showError(error) {
|
||||
try {
|
||||
let err = JSON.parse(error);
|
||||
$('.error-console').text(err.message).addClass('active');
|
||||
$('.error-console').text(err.message).fadeIn();
|
||||
} catch (err) {
|
||||
$('.error-console').text(error).addClass('active');
|
||||
$('.error-console').text(error).fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
en:
|
||||
download_landing:
|
||||
download_your_account: "Download Your Account"
|
||||
click_to_download: "Click below to download your account"
|
||||
confirm: "Download"
|
||||
download_your_account: "Download Your Comment History"
|
||||
download_details: "Your comment history will be downloaded into a .zip file. After your comment history is unzipped you will have a comma seperated value (or .csv) file that you can easily import into your favorite spreadsheet application."
|
||||
all_information_included: "For each of your comments the following information is included:"
|
||||
information_included:
|
||||
date: "When you wrote the comment"
|
||||
url: "The permalink URL for the comment"
|
||||
body: "The comment text"
|
||||
asset_url: "The URL on the article or story where the comment appears"
|
||||
confirm: "Download My Comment History"
|
||||
email:
|
||||
download:
|
||||
subject: "Your download link is ready" # TODO: replace
|
||||
download_link_ready: "Your download link is now ready, visit the following to download an archive of your account:" # TODO: replace
|
||||
download_archive: "Download Archive" # TODO: replace
|
||||
subject: "Your comments are ready for download from {0}"
|
||||
download_link_ready: "Click here to download your comments from {0} as of {1}:"
|
||||
download_archive: "Download Archive"
|
||||
error:
|
||||
DOWNLOAD_TOKEN_INVALID: "Your download link is not valid."
|
||||
|
||||
+50
-13
@@ -6,13 +6,15 @@ body, #root {
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 300px;
|
||||
max-width: 675px;
|
||||
margin: 50px auto;
|
||||
}
|
||||
|
||||
#root form {
|
||||
display: none;
|
||||
padding: 15px;
|
||||
padding: 15px 0;
|
||||
/* max-width: 400px;
|
||||
margin: 0 auto; */
|
||||
}
|
||||
|
||||
.legend {
|
||||
@@ -21,6 +23,22 @@ body, #root {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
section p, ul {
|
||||
font-family: Source Sans Pro;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 34px;
|
||||
font-size: 24px;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Source Sans Pro;
|
||||
font-size: 48px;
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
@@ -44,28 +62,47 @@ input {
|
||||
}
|
||||
|
||||
button[type="submit"] {
|
||||
border-radius: 4px;
|
||||
font-family: Source Sans Pro;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
display: block;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
background-color: #3498DB;
|
||||
margin: 10px auto;
|
||||
padding: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.error-console {
|
||||
display: none;
|
||||
margin-top: 10px;
|
||||
border-radius: 4px;
|
||||
border-radius: 2px;
|
||||
background-color: pink;
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
padding: 10px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.error-console.active {
|
||||
display: block;
|
||||
}
|
||||
ul.check_list {
|
||||
list-style-type: none;
|
||||
margin: 0 0 0 0.5em;
|
||||
}
|
||||
|
||||
ul.check_list li {
|
||||
text-indent: -1.4em;
|
||||
}
|
||||
|
||||
ul.check_list li:before {
|
||||
font-family: 'Material Icons';
|
||||
content: '\E5CA';
|
||||
color: #000;
|
||||
float: left;
|
||||
width: 1.4em;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const tokenCheck = (verifier, error, ...whitelistedErrors) => async (
|
||||
// Log out the error, slurp it and send out the predefined error to the
|
||||
// error handler.
|
||||
console.error(err);
|
||||
return next(error);
|
||||
return next(new error());
|
||||
}
|
||||
|
||||
res.status(204).end();
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
<title>Email Verification</title>
|
||||
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
|
||||
<link rel="stylesheet" href="<%= BASE_PATH %>public/css/admin.css">
|
||||
<%- include ../../partials/head %>
|
||||
<title><%= t('confirm_email.email_confirmation') %></title>
|
||||
<%- include ../../partials/account %>
|
||||
</head>
|
||||
<body class="confirm-email-page">
|
||||
<div id="root">
|
||||
<div class="error-console container"></div>
|
||||
<form id="verify-email-form" class="container">
|
||||
<legend class="legend"><%= t('confirm_email.click_to_confirm') %></legend>
|
||||
<button type="submit"><%= t('confirm_email.confirm') %></button>
|
||||
</form>
|
||||
<section class="container">
|
||||
<h1><%= t('confirm_email.email_confirmation') %></h1>
|
||||
<p><%= t('confirm_email.click_to_confirm') %></p>
|
||||
<div class="error-console"></div>
|
||||
<form id="verify-email-form">
|
||||
<button type="submit"><%= t('confirm_email.confirm') %></button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
@@ -21,9 +21,9 @@
|
||||
function showError(error) {
|
||||
try {
|
||||
let err = JSON.parse(error);
|
||||
$('.error-console').text(err.message).addClass('active');
|
||||
$('.error-console').text(err.message).fadeIn();
|
||||
} catch (err) {
|
||||
$('.error-console').text(error).addClass('active');
|
||||
$('.error-console').text(error).fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
<title>Password Reset</title>
|
||||
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
|
||||
<link rel="stylesheet" href="<%= BASE_PATH %>public/css/admin.css">
|
||||
<%- include ../../partials/head %>
|
||||
<title><%= t('password_reset.set_new_password') %></title>
|
||||
<%- include ../../partials/account %>
|
||||
</head>
|
||||
<body class="password-reset-page">
|
||||
<body>
|
||||
<div id="root">
|
||||
<div class="error-console container"></div>
|
||||
<form id="reset-password-form" class="container">
|
||||
<legend class="legend"><%= t('password_reset.set_new_password') %></legend>
|
||||
<label for="password">
|
||||
<%= t('password_reset.new_password') %>
|
||||
<input type="password" name="password" placeholder="<%= t('password_reset.new_password') %>" />
|
||||
<p><small><%= t('password_reset.new_password_help') %></small></p>
|
||||
</label>
|
||||
|
||||
<label for="confirm-password">
|
||||
<%= t('password_reset.confirm_new_password') %>
|
||||
<input type="password" name="confirm-password" placeholder="<%= t('password_reset.confirm_new_password') %>" />
|
||||
</label>
|
||||
<button type="submit"><%= t('password_reset.change_password') %></button>
|
||||
</form>
|
||||
<section class="container">
|
||||
<h1><%= t('password_reset.set_new_password') %></h1>
|
||||
<p><%= t('password_reset.change_password_help') %></p>
|
||||
<div class="error-console"></div>
|
||||
<form id="reset-password-form">
|
||||
<label for="password">
|
||||
<%= t('password_reset.new_password') %>
|
||||
<input type="password" name="password" placeholder="<%= t('password_reset.new_password') %>" />
|
||||
<p><small><%= t('password_reset.new_password_help') %></small></p>
|
||||
</label>
|
||||
<label for="confirm-password">
|
||||
<%= t('password_reset.confirm_new_password') %>
|
||||
<input type="password" name="confirm-password" placeholder="<%= t('password_reset.confirm_new_password') %>" />
|
||||
</label>
|
||||
<button type="submit"><%= t('password_reset.change_password') %></button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script>
|
||||
@@ -31,9 +30,9 @@
|
||||
function showError(error) {
|
||||
try {
|
||||
let err = JSON.parse(error);
|
||||
$('.error-console').text(err.message).addClass('active');
|
||||
$('.error-console').text(err.message).fadeIn();
|
||||
} catch (err) {
|
||||
$('.error-console').text(error).addClass('active');
|
||||
$('.error-console').text(error).fadeIn();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="<%= resolve('embed/stream/default.css') %>">
|
||||
<link rel="stylesheet" type="text/css" href="<%= resolve('embed/stream/bundle.css') %>">
|
||||
<%- include ../partials/head %>
|
||||
|
||||
@@ -13,8 +13,14 @@
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="<%= STATIC_URL %>public/img/favicon-16x16.png">
|
||||
<link rel="manifest" href="<%= STATIC_URL %>public/manifest.json">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600" rel="stylesheet">
|
||||
|
||||
<%_ if (locals.customCssUrl) { _%>
|
||||
<link href="<%= customCssUrl %>" rel="stylesheet" type="text/css">
|
||||
<%_ } _%>
|
||||
<%- include data %>
|
||||
|
||||
<base href="<%= BASE_URL %>"/>
|
||||
|
||||
Reference in New Issue
Block a user