Compare commits
5 Commits
34403b8ec7
...
9f736d4731
Author | SHA1 | Date |
---|---|---|
Robbie Antenesse | 9f736d4731 | |
Robbie Antenesse | 1aa4d6346d | |
Robbie Antenesse | e3b4809478 | |
Robbie Antenesse | f12f8b987a | |
Robbie Antenesse | e0a8c21051 |
|
@ -13,6 +13,7 @@ export class LoginController extends ViewController {
|
|||
createDisplayName: '',
|
||||
createPassword: '',
|
||||
createConfirm: '',
|
||||
createPermission: 100,
|
||||
},
|
||||
loginError: '',
|
||||
createError: '',
|
||||
|
@ -146,7 +147,8 @@ export class LoginController extends ViewController {
|
|||
createEmail,
|
||||
createUsername,
|
||||
createDisplayName,
|
||||
createPassword
|
||||
createPassword,
|
||||
createPermission
|
||||
} = this.state.fieldValues;
|
||||
|
||||
fetch('/api/account/create', {
|
||||
|
@ -159,6 +161,7 @@ export class LoginController extends ViewController {
|
|||
username: createUsername,
|
||||
displayName: createDisplayName,
|
||||
password: createPassword,
|
||||
permissionLevel: createPermission,
|
||||
}),
|
||||
}).then(response => response.json())
|
||||
.then(response => {
|
||||
|
|
|
@ -127,6 +127,22 @@ export const loginView = (state, emit, i18n) => {
|
|||
onkeyup=${e => { if (e.key === 'Enter') controller.validateCreateAccount() }}
|
||||
>
|
||||
</label>
|
||||
<label>
|
||||
<span>${__('login.permissions.label')}</span>
|
||||
<select name="new_visibility"
|
||||
onchange=${e => controller.state.fieldValues.createPermission = e.target.value.trim()}
|
||||
>
|
||||
<option value="100" ${controller.state.fieldValues.createPermission === 100 ? 'selected' : null}>
|
||||
${__('login.permissions.public')}
|
||||
</option>
|
||||
<option value="33" ${controller.state.fieldValues.createPermission === 33 ? 'selected' : null}>
|
||||
${__('login.permissions.following')}
|
||||
</option>
|
||||
<option value="0" ${controller.state.fieldValues.createPermission === 0 ? 'selected' : null}>
|
||||
${__('login.permissions.private')}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
${
|
||||
controller.state.createError === ''
|
||||
? null
|
||||
|
|
|
@ -27,6 +27,7 @@ class AccountController {
|
|||
if (typeof createAccountData.email === 'undefined'
|
||||
|| typeof createAccountData.username === 'undefined'
|
||||
|| typeof createAccountData.password === 'undefined'
|
||||
|| typeof createAccountData.permissionLevel === 'undefined'
|
||||
|| createAccountData.password === '') {
|
||||
return {
|
||||
error: true,
|
||||
|
@ -45,6 +46,12 @@ class AccountController {
|
|||
message: 'api.account.create.invalid_username',
|
||||
};
|
||||
}
|
||||
if (![100, 33, 0].includes(createAccountData.permissionLevel)) {
|
||||
return {
|
||||
error: true,
|
||||
message: 'api.account.create.invalid_permissionLevel',
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -75,6 +82,7 @@ class AccountController {
|
|||
username: formData.username.toString().trim(),
|
||||
displayName: displayName.length > 0 ? displayName : 'A Bee',
|
||||
password: formData.password,
|
||||
permissionLevel: formData.permissionLevel,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,7 +138,7 @@ class AccountController {
|
|||
return true;
|
||||
}
|
||||
|
||||
async createUser (email, username, displayName, password, needsConfirmation) {
|
||||
async createUser (email, username, displayName, permissionLevel, password, needsConfirmation) {
|
||||
const hashData = AccountController.hashPassword(password);
|
||||
// The data should already have gone through AccountController.cleanCreateAccountFormData()
|
||||
try {
|
||||
|
@ -138,6 +146,7 @@ class AccountController {
|
|||
email,
|
||||
username,
|
||||
displayName,
|
||||
permissionLevel,
|
||||
passwordHash: hashData.hash,
|
||||
passwordSalt: hashData.salt,
|
||||
accountConfirm: needsConfirmation ? crypto.randomBytes(32).toString('hex') : null,
|
||||
|
|
|
@ -286,6 +286,25 @@ class ShelfController {
|
|||
|
||||
return success;
|
||||
}
|
||||
|
||||
async deleteShelfItem(shelfItem) {
|
||||
// Only fully remove if no statuses are associated
|
||||
const statuses = await shelfItem.getStatuses();
|
||||
const options = {};
|
||||
if (statuses.length < 1) {
|
||||
options.force = true;
|
||||
}
|
||||
|
||||
const success = await shelfItem.destroy(options);
|
||||
|
||||
if (!success) {
|
||||
return {
|
||||
error: shelfItem,
|
||||
};
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ShelfController;
|
|
@ -41,6 +41,12 @@
|
|||
"confirm_password": "Confirm Password",
|
||||
"username": "Username",
|
||||
"display_name": "Display Name",
|
||||
"permissions": {
|
||||
"label": "Profile Visibility",
|
||||
"public": "Public (anyone can see you)",
|
||||
"following": "Following (only accounts you follow can see you)",
|
||||
"private": "Private (nobody can see you)"
|
||||
},
|
||||
"create_account_button": "Create Account!",
|
||||
"login_required_field_blank": "You must enter both a valid email address and password.",
|
||||
"create_required_field_blank": "You must complete all required fields.",
|
||||
|
@ -93,7 +99,8 @@
|
|||
"fail": "Something went wrong and the account could not be created. Please try again later.",
|
||||
"required_data_missing": "Could not create account because required data is missing.",
|
||||
"invalid_email": "The email address entered is not valid.",
|
||||
"invalid_username": "The username entered is not valid. Usernames must be at least 2 characters long and can only contain letters a–z, numbers 0–9, and underscores",
|
||||
"invalid_username": "The username entered is not valid. Usernames must be at least 2 characters long and can only contain letters a–z, numbers 0–9, and underscores.",
|
||||
"invalid_permissionLevel": "The permissionLevel entered is not valid. PermissionLevel must be one 100, 33, or 0. Contact the front-end developer and ask them to fix their permission selector.",
|
||||
"success": "Account created successfully! You may now log in using the email address and password you provided."
|
||||
},
|
||||
"confirm": {
|
||||
|
|
|
@ -11,7 +11,12 @@ async function routes(fastify, options) {
|
|||
response.locale = fastify.i18n[request.params.locale];
|
||||
}
|
||||
|
||||
return response;
|
||||
return reply.setCookie('lang', request.params.locale, {
|
||||
path: '/',
|
||||
expires: new Date('December 31, 9999'), // Don't expire
|
||||
maxAge: new Date('December 31, 9999'), // Both are set as a "just in case"
|
||||
sameSite: true, // Prevents the cookie from being used outside of this site
|
||||
}).send(response);
|
||||
});
|
||||
|
||||
fastify.get('/locales/:locale/page/:page', async (request, reply) => {
|
||||
|
|
|
@ -82,6 +82,9 @@ fastify.addHook('onRequest', async (request, reply) => {
|
|||
request.user = user;
|
||||
}
|
||||
}
|
||||
if (typeof request.cookies.lang !== 'undefined') {
|
||||
request.language = request.cookies.lang;
|
||||
}
|
||||
});
|
||||
|
||||
// Store i18n files in fastify object and register locales routes
|
||||
|
|
|
@ -30,14 +30,14 @@ async function routes(fastify, options) {
|
|||
return reply.code(400).send(canCreateUser);
|
||||
}
|
||||
|
||||
const newUser = await account.createUser(formData.email, formData.username, formData.displayName, formData.password, fastify.canEmail);
|
||||
|
||||
const newUser = await account.createUser(formData.email, formData.username, formData.displayName, formData.permissionLevel, formData.password, fastify.canEmail);
|
||||
|
||||
if (typeof newUser.error !== 'undefined' && newUser.error !== false) {
|
||||
newUser.message = 'api.account.create.fail';
|
||||
return reply.code(400).send(newUser);
|
||||
}
|
||||
|
||||
const shelf = new ShelfController(fastify.models.Shelf, fastify.models.ShelfItem);
|
||||
const shelf = new ShelfController(fastify.models, null);
|
||||
const defaultShelvesCreated = await shelf.createDefaultShelves(newUser);
|
||||
|
||||
// If some of the default shelves are not created successfully, delete the user and send an error
|
||||
|
|
|
@ -18,7 +18,7 @@ async function routes(fastify, options) {
|
|||
const shelfController = new ShelfController(fastify.models);
|
||||
|
||||
const shelves = await request.user.getShelves({
|
||||
attributes: ['id', 'name', 'isDeletable', 'isPublic', 'updatedAt'],
|
||||
attributes: ['id', 'name', 'isDeletable', 'permissionLevel', 'updatedAt'],
|
||||
});
|
||||
|
||||
return shelves.map(shelf => {
|
||||
|
@ -258,11 +258,11 @@ async function routes(fastify, options) {
|
|||
|
||||
const shelfController = new ShelfController(fastify.models, request.language);
|
||||
|
||||
const shelfItem = await shelfController.moveShelfItem(shelfItem, toShelf);
|
||||
const moveSuccess = await shelfController.moveShelfItem(shelfItem, toShelf);
|
||||
|
||||
if (typeof shelfItem.error !== 'undefined') {
|
||||
if (typeof moveSuccess.error !== 'undefined') {
|
||||
return reply.code(400).send({
|
||||
error: shelfItem.error,
|
||||
error: moveSuccess.error,
|
||||
message: 'api.shelf.moveItem.could_not_move',
|
||||
});
|
||||
}
|
||||
|
@ -272,6 +272,49 @@ async function routes(fastify, options) {
|
|||
message: 'api.shelf.moveItem.success',
|
||||
});
|
||||
});
|
||||
|
||||
fastify.post('/api/shelf/deleteItem', async (request, reply) => {
|
||||
if (!request.isLoggedInUser) {
|
||||
return reply.code(401).send({
|
||||
error: true,
|
||||
message: 'api.not_logged_in',
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof request.body.itemId === 'undefined') {
|
||||
return reply.code(400).send({
|
||||
error: true,
|
||||
message: 'api.shelf.deleteItem.missing_item_id',
|
||||
});
|
||||
}
|
||||
|
||||
const shelfItem = await fastify.models.ShelfItem.findByPk(request.body.itemId, {
|
||||
include: [ fastify.models.Shelf ],
|
||||
});
|
||||
|
||||
if (!ShelfController.userOwnsShelf(request.user, shelfItem.Shelf)) {
|
||||
return reply.code(403).send({
|
||||
error: true,
|
||||
message: 'api.shelf.not_owner',
|
||||
});
|
||||
}
|
||||
|
||||
const shelfController = new ShelfController(fastify.models, request.language);
|
||||
|
||||
const deleteSuccess = await shelfController.deleteShelfItem(shelfItem);
|
||||
|
||||
if (typeof deleteSuccess.error !== 'undefined') {
|
||||
return reply.code(400).send({
|
||||
error: deleteSuccess.error,
|
||||
message: 'api.shelf.deleteItem.could_not_delete',
|
||||
});
|
||||
}
|
||||
|
||||
return reply.send({
|
||||
error: false,
|
||||
message: 'api.shelf.deleteItem.success',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = routes;
|
|
@ -18,6 +18,7 @@ module.exports = sequelize => sequelize.define('Review', {
|
|||
permissionLevel: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
references: {
|
||||
model: sequelize.models.PermissionLevel,
|
||||
key: 'id',
|
||||
|
|
|
@ -25,6 +25,7 @@ module.exports = sequelize => sequelize.define('Shelf', {
|
|||
permissionLevel: {
|
||||
type: Sequelize.NUMBER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
references: {
|
||||
model: sequelize.models.PermissionLevel,
|
||||
key: 'id',
|
||||
|
|
|
@ -51,4 +51,5 @@ module.exports = sequelize => sequelize.define('ShelfItem', {
|
|||
fields: ['shelfId'],
|
||||
},
|
||||
],
|
||||
paranoid: true, // Keep shelfItems in database just in case there are Statuses associated
|
||||
});
|
|
@ -18,6 +18,7 @@ module.exports = sequelize => sequelize.define('Status', {
|
|||
permissionLevel: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
references: {
|
||||
model: sequelize.models.PermissionLevel,
|
||||
key: 'id',
|
||||
|
|
|
@ -34,6 +34,7 @@ module.exports = sequelize => sequelize.define('User', {
|
|||
permissionLevel: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
defaultValue: 0,
|
||||
references: {
|
||||
model: sequelize.models.PermissionLevel,
|
||||
key: 'id',
|
||||
|
|
Loading…
Reference in New Issue