mirror of
				https://github.com/xfarrow/blink
				synced 2025-06-27 09:03:02 +02:00 
			
		
		
		
	ran 'npx standard --fix'
This commit is contained in:
		@@ -2,65 +2,64 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Importing modules
 | 
			
		||||
// TODO: clean up
 | 
			
		||||
require('dotenv').config();
 | 
			
		||||
const express = require('express');
 | 
			
		||||
const cors = require('cors');
 | 
			
		||||
const rateLimit = require('express-rate-limit');
 | 
			
		||||
const personRoutes = require('./routes/person_routes.js');
 | 
			
		||||
const organizationRoutes = require('./routes/organization_routes.js');
 | 
			
		||||
const organizationAdminRoutes = require('./routes/organization_admin_routes.js');
 | 
			
		||||
require('dotenv').config()
 | 
			
		||||
const express = require('express')
 | 
			
		||||
const cors = require('cors')
 | 
			
		||||
const rateLimit = require('express-rate-limit')
 | 
			
		||||
const personRoutes = require('./routes/person_routes.js')
 | 
			
		||||
const organizationRoutes = require('./routes/organization_routes.js')
 | 
			
		||||
const organizationAdminRoutes = require('./routes/organization_admin_routes.js')
 | 
			
		||||
const organizationPostRoutes = require('./routes/organization_post_routes.js')
 | 
			
		||||
const jwt_utils = require('./utils/jwt_utils.js');
 | 
			
		||||
 | 
			
		||||
const jwt_utils = require('./utils/jwt_utils.js')
 | 
			
		||||
 | 
			
		||||
// Application configuration
 | 
			
		||||
const app = express();
 | 
			
		||||
app.use(express.json()); // Middleware which parses JSON for POST requests
 | 
			
		||||
app.use(cors()); // Enable CORS for all routes
 | 
			
		||||
const app = express()
 | 
			
		||||
app.use(express.json()) // Middleware which parses JSON for POST requests
 | 
			
		||||
app.use(cors()) // Enable CORS for all routes
 | 
			
		||||
app.use(rateLimit({
 | 
			
		||||
  windowMs: process.env.LIMITER_WINDOW,
 | 
			
		||||
  max: process.env.LIMITER_MAXIMUM_PER_WINDOW,
 | 
			
		||||
  message: {error : "Too many requests from this IP, please try again later"}
 | 
			
		||||
})); // Apply the rate limiter middleware to all routes
 | 
			
		||||
  message: { error: 'Too many requests from this IP, please try again later' }
 | 
			
		||||
})) // Apply the rate limiter middleware to all routes
 | 
			
		||||
 | 
			
		||||
const publicRoutes = express.Router();
 | 
			
		||||
publicRoutes.post('/register', personRoutes.registerPerson);
 | 
			
		||||
publicRoutes.post('/login', personRoutes.login);
 | 
			
		||||
const publicRoutes = express.Router()
 | 
			
		||||
publicRoutes.post('/register', personRoutes.registerPerson)
 | 
			
		||||
publicRoutes.post('/login', personRoutes.login)
 | 
			
		||||
 | 
			
		||||
const protectedRoutes = express.Router();
 | 
			
		||||
protectedRoutes.use(jwt_utils.verifyToken);
 | 
			
		||||
protectedRoutes.get('/person/myself', personRoutes.getMyself);
 | 
			
		||||
protectedRoutes.get('/person/:id', personRoutes.getPerson);
 | 
			
		||||
protectedRoutes.put('/person/:id', personRoutes.updatePerson);
 | 
			
		||||
protectedRoutes.delete('/person/delete', personRoutes.deletePerson);
 | 
			
		||||
protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin);
 | 
			
		||||
protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin);
 | 
			
		||||
protectedRoutes.post('/organization', organizationRoutes.createOrganization);
 | 
			
		||||
protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization);
 | 
			
		||||
protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization);
 | 
			
		||||
protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization);
 | 
			
		||||
protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost);
 | 
			
		||||
protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost);
 | 
			
		||||
const protectedRoutes = express.Router()
 | 
			
		||||
protectedRoutes.use(jwt_utils.verifyToken)
 | 
			
		||||
protectedRoutes.get('/person/myself', personRoutes.getMyself)
 | 
			
		||||
protectedRoutes.get('/person/:id', personRoutes.getPerson)
 | 
			
		||||
protectedRoutes.put('/person/:id', personRoutes.updatePerson)
 | 
			
		||||
protectedRoutes.delete('/person/delete', personRoutes.deletePerson)
 | 
			
		||||
protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin)
 | 
			
		||||
protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin)
 | 
			
		||||
protectedRoutes.post('/organization', organizationRoutes.createOrganization)
 | 
			
		||||
protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization)
 | 
			
		||||
protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization)
 | 
			
		||||
protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization)
 | 
			
		||||
protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost)
 | 
			
		||||
protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost)
 | 
			
		||||
 | 
			
		||||
// Mounting routes
 | 
			
		||||
app.use('/api', publicRoutes); // Routes not requiring token
 | 
			
		||||
app.use('/api', protectedRoutes); // Routes requiring token
 | 
			
		||||
app.use('/api', publicRoutes) // Routes not requiring token
 | 
			
		||||
app.use('/api', protectedRoutes) // Routes requiring token
 | 
			
		||||
 | 
			
		||||
// Start the server. Default port is 3000
 | 
			
		||||
const port = process.env.API_SERVER_PORT || 3000;
 | 
			
		||||
const port = process.env.API_SERVER_PORT || 3000
 | 
			
		||||
app.listen(port, () => {
 | 
			
		||||
  console.log(`Blink API server is running on port ${port}`);
 | 
			
		||||
});
 | 
			
		||||
  console.log(`Blink API server is running on port ${port}`)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
module.exports = app;
 | 
			
		||||
module.exports = app
 | 
			
		||||
 
 | 
			
		||||
@@ -2,116 +2,116 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const knex = require('../utils/knex_config');
 | 
			
		||||
const knex = require('../utils/knex_config')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Create Organization object
 | 
			
		||||
 * @param {*} name 
 | 
			
		||||
 * @param {*} location 
 | 
			
		||||
 * @param {*} description 
 | 
			
		||||
 * @param {*} is_hiring 
 | 
			
		||||
 * @returns 
 | 
			
		||||
 * @param {*} name
 | 
			
		||||
 * @param {*} location
 | 
			
		||||
 * @param {*} description
 | 
			
		||||
 * @param {*} is_hiring
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
function organization(name, location, description, is_hiring){
 | 
			
		||||
    const organization = {
 | 
			
		||||
        name: name,
 | 
			
		||||
        location: location,
 | 
			
		||||
        description: description,
 | 
			
		||||
        is_hiring: is_hiring
 | 
			
		||||
    };
 | 
			
		||||
    return organization;
 | 
			
		||||
function organization (name, location, description, is_hiring) {
 | 
			
		||||
  const organization = {
 | 
			
		||||
    name,
 | 
			
		||||
    location,
 | 
			
		||||
    description,
 | 
			
		||||
    is_hiring
 | 
			
		||||
  }
 | 
			
		||||
  return organization
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Gets an Organization by its identifier
 | 
			
		||||
 * @param {*} id 
 | 
			
		||||
 * @returns 
 | 
			
		||||
 * @param {*} id
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
async function getOrganizationById(id){
 | 
			
		||||
async function getOrganizationById (id) {
 | 
			
		||||
  const organization = await knex('Organization')
 | 
			
		||||
    .where('id', id)
 | 
			
		||||
    .select('*')
 | 
			
		||||
    .first();
 | 
			
		||||
  return organization;
 | 
			
		||||
    .first()
 | 
			
		||||
  return organization
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Insert an Organization and its relative Administrator
 | 
			
		||||
 * @param {*} organization 
 | 
			
		||||
 * @param {*} organization
 | 
			
		||||
 */
 | 
			
		||||
async function insertOrganization(organization, organizationAdministratorId){
 | 
			
		||||
    await knex.transaction(async (trx) => {
 | 
			
		||||
        // We have to insert either both in Organization and in OrganizationAdministrator
 | 
			
		||||
        // or in neither
 | 
			
		||||
        const organizationResult = await trx('Organization')
 | 
			
		||||
          .insert(organization, '*');
 | 
			
		||||
  
 | 
			
		||||
        // Inserting in the "OrganizationAdministrator" table
 | 
			
		||||
        await trx('OrganizationAdministrator')
 | 
			
		||||
          .insert({
 | 
			
		||||
            id_person: organizationAdministratorId,
 | 
			
		||||
            id_organization: organizationResult[0].id,
 | 
			
		||||
          });
 | 
			
		||||
  });
 | 
			
		||||
async function insertOrganization (organization, organizationAdministratorId) {
 | 
			
		||||
  await knex.transaction(async (trx) => {
 | 
			
		||||
    // We have to insert either both in Organization and in OrganizationAdministrator
 | 
			
		||||
    // or in neither
 | 
			
		||||
    const organizationResult = await trx('Organization')
 | 
			
		||||
      .insert(organization, '*')
 | 
			
		||||
 | 
			
		||||
    // Inserting in the "OrganizationAdministrator" table
 | 
			
		||||
    await trx('OrganizationAdministrator')
 | 
			
		||||
      .insert({
 | 
			
		||||
        id_person: organizationAdministratorId,
 | 
			
		||||
        id_organization: organizationResult[0].id
 | 
			
		||||
      })
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Updates an Organization specified by the OrganizationId, if and
 | 
			
		||||
 * only if the specified personId is one of its Administrator
 | 
			
		||||
 * @param {*} organization 
 | 
			
		||||
 * @param {*} organizationId 
 | 
			
		||||
 * @param {*} personId 
 | 
			
		||||
 * @param {*} organization
 | 
			
		||||
 * @param {*} organizationId
 | 
			
		||||
 * @param {*} personId
 | 
			
		||||
 * @returns true if the row was updated, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
async function updateOrganizationIfAdministrator(organization, organizationId, personId){
 | 
			
		||||
      // // const isOrganizationAdmin = await knex('OrganizationAdministrator')
 | 
			
		||||
      // // .where('id_person', req.jwt.person_id)
 | 
			
		||||
      // // .where('id_organization', req.params.id)
 | 
			
		||||
      // // .select('*')
 | 
			
		||||
      // // .first();
 | 
			
		||||
  
 | 
			
		||||
      // // // This introduces a Time of check Time of use weakeness
 | 
			
		||||
      // // // which could'have been fixed by either
 | 
			
		||||
      // // // 1) Using "whereExists", thanks to the "it's easier to ask for
 | 
			
		||||
      // // // forgiveness than for permission" padarigm. Or,
 | 
			
		||||
      // // // 2) Using a serializable transaction.
 | 
			
		||||
      // // //
 | 
			
		||||
      // // // The undersigned chose not to follow these approaches because
 | 
			
		||||
      // // // this does not introduces any serious vulnerability. In this
 | 
			
		||||
      // // // way it seems more readable.
 | 
			
		||||
  
 | 
			
		||||
      // // if(!isOrganizationAdmin){
 | 
			
		||||
      // //   return res.status(403).json({error : "Forbidden"});
 | 
			
		||||
      // // }
 | 
			
		||||
  
 | 
			
		||||
      // // await knex('Organization')
 | 
			
		||||
      // // .where('id', req.params.id)
 | 
			
		||||
      // // .update({
 | 
			
		||||
      // //   name: req.body.name,
 | 
			
		||||
      // //   location: req.body.location,
 | 
			
		||||
      // //   description: req.body.description,
 | 
			
		||||
      // //   is_hiring: req.body.is_hiring
 | 
			
		||||
      // // });
 | 
			
		||||
async function updateOrganizationIfAdministrator (organization, organizationId, personId) {
 | 
			
		||||
  // // const isOrganizationAdmin = await knex('OrganizationAdministrator')
 | 
			
		||||
  // // .where('id_person', req.jwt.person_id)
 | 
			
		||||
  // // .where('id_organization', req.params.id)
 | 
			
		||||
  // // .select('*')
 | 
			
		||||
  // // .first();
 | 
			
		||||
 | 
			
		||||
  // // // This introduces a Time of check Time of use weakeness
 | 
			
		||||
  // // // which could'have been fixed by either
 | 
			
		||||
  // // // 1) Using "whereExists", thanks to the "it's easier to ask for
 | 
			
		||||
  // // // forgiveness than for permission" padarigm. Or,
 | 
			
		||||
  // // // 2) Using a serializable transaction.
 | 
			
		||||
  // // //
 | 
			
		||||
  // // // The undersigned chose not to follow these approaches because
 | 
			
		||||
  // // // this does not introduces any serious vulnerability. In this
 | 
			
		||||
  // // // way it seems more readable.
 | 
			
		||||
 | 
			
		||||
  // // if(!isOrganizationAdmin){
 | 
			
		||||
  // //   return res.status(403).json({error : "Forbidden"});
 | 
			
		||||
  // // }
 | 
			
		||||
 | 
			
		||||
  // // await knex('Organization')
 | 
			
		||||
  // // .where('id', req.params.id)
 | 
			
		||||
  // // .update({
 | 
			
		||||
  // //   name: req.body.name,
 | 
			
		||||
  // //   location: req.body.location,
 | 
			
		||||
  // //   description: req.body.description,
 | 
			
		||||
  // //   is_hiring: req.body.is_hiring
 | 
			
		||||
  // // });
 | 
			
		||||
 | 
			
		||||
  const numberOfUpdatedRows = await knex('Organization')
 | 
			
		||||
    .where('id', organizationId)
 | 
			
		||||
    .whereExists(function(){
 | 
			
		||||
    .whereExists(function () {
 | 
			
		||||
      this.select('*')
 | 
			
		||||
        .from('OrganizationAdministrator')
 | 
			
		||||
        .where('id_person', personId)
 | 
			
		||||
        .where('id_organization', organizationId)
 | 
			
		||||
    })
 | 
			
		||||
    .update(organization);
 | 
			
		||||
  return numberOfUpdatedRows == 1;
 | 
			
		||||
    .update(organization)
 | 
			
		||||
  return numberOfUpdatedRows == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -121,17 +121,17 @@ async function updateOrganizationIfAdministrator(organization, organizationId, p
 | 
			
		||||
 * @param {*} personId PersonId of the supposedly administrator
 | 
			
		||||
 * @returns true if the Organization was successfully deleted, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
async function deleteOrganizationIfAdmin(organizationId, personId){
 | 
			
		||||
async function deleteOrganizationIfAdmin (organizationId, personId) {
 | 
			
		||||
  const numberOfDeletedRows = await knex('Organization')
 | 
			
		||||
    .where({ id: organizationId })
 | 
			
		||||
    .whereExists(function(){
 | 
			
		||||
    .whereExists(function () {
 | 
			
		||||
      this.select('*')
 | 
			
		||||
        .from('OrganizationAdministrator')
 | 
			
		||||
        .where('id_person', personId)
 | 
			
		||||
        .where('id_organization', organizationId)
 | 
			
		||||
    })
 | 
			
		||||
    .del();
 | 
			
		||||
  return numberOfDeletedRows == 1;
 | 
			
		||||
    .del()
 | 
			
		||||
  return numberOfDeletedRows == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Exporting a function
 | 
			
		||||
@@ -144,4 +144,4 @@ module.exports = {
 | 
			
		||||
  updateOrganizationIfAdministrator,
 | 
			
		||||
  updateOrganizationIfAdministrator,
 | 
			
		||||
  deleteOrganizationIfAdmin
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,40 +2,40 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const knex = require('../utils/knex_config');
 | 
			
		||||
const bcrypt = require('bcrypt');
 | 
			
		||||
const knex = require('../utils/knex_config')
 | 
			
		||||
const bcrypt = require('bcrypt')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates Person object by the specified fields
 | 
			
		||||
 * @param {*} email 
 | 
			
		||||
 * @param {*} password 
 | 
			
		||||
 * @param {*} display_name 
 | 
			
		||||
 * @param {*} date_of_birth 
 | 
			
		||||
 * @param {*} available 
 | 
			
		||||
 * @param {*} enabled 
 | 
			
		||||
 * @param {*} place_of_living 
 | 
			
		||||
 * @returns 
 | 
			
		||||
 * @param {*} email
 | 
			
		||||
 * @param {*} password
 | 
			
		||||
 * @param {*} display_name
 | 
			
		||||
 * @param {*} date_of_birth
 | 
			
		||||
 * @param {*} available
 | 
			
		||||
 * @param {*} enabled
 | 
			
		||||
 * @param {*} place_of_living
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
function person(email, password, display_name, date_of_birth, available, enabled, place_of_living) {
 | 
			
		||||
    const person = {
 | 
			
		||||
        email: email.toLowerCase(),
 | 
			
		||||
        password: password,
 | 
			
		||||
        display_name: display_name,
 | 
			
		||||
        date_of_birth: date_of_birth,
 | 
			
		||||
        available: available,
 | 
			
		||||
        enabled: enabled,
 | 
			
		||||
        place_of_living: place_of_living
 | 
			
		||||
    };
 | 
			
		||||
    return person;
 | 
			
		||||
function person (email, password, display_name, date_of_birth, available, enabled, place_of_living) {
 | 
			
		||||
  const person = {
 | 
			
		||||
    email: email.toLowerCase(),
 | 
			
		||||
    password,
 | 
			
		||||
    display_name,
 | 
			
		||||
    date_of_birth,
 | 
			
		||||
    available,
 | 
			
		||||
    enabled,
 | 
			
		||||
    place_of_living
 | 
			
		||||
  }
 | 
			
		||||
  return person
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -43,22 +43,22 @@ function person(email, password, display_name, date_of_birth, available, enabled
 | 
			
		||||
 * @param {*} email email to look the Person for
 | 
			
		||||
 * @returns the Person object
 | 
			
		||||
 */
 | 
			
		||||
async function getPersonByEmail(email){
 | 
			
		||||
    return await knex('Person')
 | 
			
		||||
        .where('email', email.toLowerCase())
 | 
			
		||||
        .first();
 | 
			
		||||
async function getPersonByEmail (email) {
 | 
			
		||||
  return await knex('Person')
 | 
			
		||||
    .where('email', email.toLowerCase())
 | 
			
		||||
    .first()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get Person by Id
 | 
			
		||||
 * @param {*} id - The id to look the person for
 | 
			
		||||
 * @returns 
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
async function getPersonById(id){
 | 
			
		||||
    return await knex('Person')
 | 
			
		||||
      .select('*')
 | 
			
		||||
      .where({ id: id })
 | 
			
		||||
      .first();
 | 
			
		||||
async function getPersonById (id) {
 | 
			
		||||
  return await knex('Person')
 | 
			
		||||
    .select('*')
 | 
			
		||||
    .where({ id })
 | 
			
		||||
    .first()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -67,27 +67,27 @@ async function getPersonById(id){
 | 
			
		||||
 * @param {*} person A Person object
 | 
			
		||||
 * @param {*} activationLink the activationLink identifier
 | 
			
		||||
 */
 | 
			
		||||
async function registerPerson(person, activationLink){
 | 
			
		||||
    // We need to insert either both in the "Person" table
 | 
			
		||||
    // and in the "ActivationLink" one, or in neither
 | 
			
		||||
    await knex.transaction(async (tr) => {
 | 
			
		||||
      const personIdResult = await tr('Person')
 | 
			
		||||
        .insert({ 
 | 
			
		||||
          email: person.email.toLowerCase(), 
 | 
			
		||||
          password: person.password,
 | 
			
		||||
          display_name: person.display_name,
 | 
			
		||||
          date_of_birth: person.date_of_birth,
 | 
			
		||||
          available: person.available,
 | 
			
		||||
          enabled: person.enabled,
 | 
			
		||||
          place_of_living: person.place_of_living
 | 
			
		||||
        })
 | 
			
		||||
        .returning("id");
 | 
			
		||||
      await tr('ActivationLink')
 | 
			
		||||
        .insert({
 | 
			
		||||
          person_id: personIdResult[0].id,
 | 
			
		||||
          identifier: activationLink
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
async function registerPerson (person, activationLink) {
 | 
			
		||||
  // We need to insert either both in the "Person" table
 | 
			
		||||
  // and in the "ActivationLink" one, or in neither
 | 
			
		||||
  await knex.transaction(async (tr) => {
 | 
			
		||||
    const personIdResult = await tr('Person')
 | 
			
		||||
      .insert({
 | 
			
		||||
        email: person.email.toLowerCase(),
 | 
			
		||||
        password: person.password,
 | 
			
		||||
        display_name: person.display_name,
 | 
			
		||||
        date_of_birth: person.date_of_birth,
 | 
			
		||||
        available: person.available,
 | 
			
		||||
        enabled: person.enabled,
 | 
			
		||||
        place_of_living: person.place_of_living
 | 
			
		||||
      })
 | 
			
		||||
      .returning('id')
 | 
			
		||||
    await tr('ActivationLink')
 | 
			
		||||
      .insert({
 | 
			
		||||
        person_id: personIdResult[0].id,
 | 
			
		||||
        identifier: activationLink
 | 
			
		||||
      })
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -95,22 +95,22 @@ async function registerPerson(person, activationLink){
 | 
			
		||||
 * Used for log-in
 | 
			
		||||
 * @param {*} email
 | 
			
		||||
 * @param {*} password
 | 
			
		||||
 * @returns 
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
async function getPersonByEmailAndPassword(email, password){
 | 
			
		||||
    const person = await knex('Person')
 | 
			
		||||
      .where('email', email.toLowerCase())
 | 
			
		||||
      .where('enabled', true)
 | 
			
		||||
      .select('*')
 | 
			
		||||
      .first();
 | 
			
		||||
async function getPersonByEmailAndPassword (email, password) {
 | 
			
		||||
  const person = await knex('Person')
 | 
			
		||||
    .where('email', email.toLowerCase())
 | 
			
		||||
    .where('enabled', true)
 | 
			
		||||
    .select('*')
 | 
			
		||||
    .first()
 | 
			
		||||
 | 
			
		||||
    if(person){
 | 
			
		||||
      const passwordMatches = await bcrypt.compare(password, person.password);
 | 
			
		||||
      if (passwordMatches) {
 | 
			
		||||
        return person;
 | 
			
		||||
      }
 | 
			
		||||
  if (person) {
 | 
			
		||||
    const passwordMatches = await bcrypt.compare(password, person.password)
 | 
			
		||||
    if (passwordMatches) {
 | 
			
		||||
      return person
 | 
			
		||||
    }
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
  return null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -118,32 +118,31 @@ async function getPersonByEmailAndPassword(email, password){
 | 
			
		||||
 * @param {*} person The Person to update
 | 
			
		||||
 * @param {*} person_id The database id of the Person to update
 | 
			
		||||
 */
 | 
			
		||||
async function updatePerson(person, person_id){
 | 
			
		||||
    await knex('Person')
 | 
			
		||||
      .where('id', person_id)
 | 
			
		||||
      .update(person);
 | 
			
		||||
async function updatePerson (person, person_id) {
 | 
			
		||||
  await knex('Person')
 | 
			
		||||
    .where('id', person_id)
 | 
			
		||||
    .update(person)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Deletes a Person specified by its database id.
 | 
			
		||||
 * @param {*} person_id 
 | 
			
		||||
 * @param {*} person_id
 | 
			
		||||
 */
 | 
			
		||||
async function deletePerson(person_id){
 | 
			
		||||
    await knex('Person')
 | 
			
		||||
      .where({id : person_id})
 | 
			
		||||
      .del();
 | 
			
		||||
async function deletePerson (person_id) {
 | 
			
		||||
  await knex('Person')
 | 
			
		||||
    .where({ id: person_id })
 | 
			
		||||
    .del()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Exporting a function
 | 
			
		||||
// means making a JavaScript function defined in one
 | 
			
		||||
// module available for use in another module.
 | 
			
		||||
module.exports = {
 | 
			
		||||
    person,
 | 
			
		||||
    getPersonByEmail,
 | 
			
		||||
    getPersonById,
 | 
			
		||||
    getPersonByEmailAndPassword,
 | 
			
		||||
    registerPerson,
 | 
			
		||||
    updatePerson,
 | 
			
		||||
    deletePerson
 | 
			
		||||
};
 | 
			
		||||
  person,
 | 
			
		||||
  getPersonByEmail,
 | 
			
		||||
  getPersonById,
 | 
			
		||||
  getPersonByEmailAndPassword,
 | 
			
		||||
  registerPerson,
 | 
			
		||||
  updatePerson,
 | 
			
		||||
  deletePerson
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,75 +2,71 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const knex = require('../utils/knex_config');
 | 
			
		||||
const organization_admin_model = require('../models/organization_admin_model');
 | 
			
		||||
const knex = require('../utils/knex_config')
 | 
			
		||||
const organization_admin_model = require('../models/organization_admin_model')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POST Method
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Add an Administrator to an Organization. Allowed only if the
 | 
			
		||||
 * logged user is an Administrator themselves.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): organization_id, person_id
 | 
			
		||||
 */
 | 
			
		||||
async function addOrganizationAdmin(req, res){
 | 
			
		||||
async function addOrganizationAdmin (req, res) {
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.organization_id || !req.body.person_id) {
 | 
			
		||||
    return res.status(400).json({ error: 'Invalid request' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // Ensure that the required fields are present before proceeding
 | 
			
		||||
    if (!req.body.organization_id || !req.body.person_id) {
 | 
			
		||||
      return res.status(400).json({ error : "Invalid request"});
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    try {
 | 
			
		||||
      const isPersonAdmin = await organization_admin_model.isPersonAdmin(req.jwt.person_id, req.body.organization_id);
 | 
			
		||||
      // TOC/TOU
 | 
			
		||||
      if(!isPersonAdmin){
 | 
			
		||||
        return res.status(401).json({error : "Forbidden"});
 | 
			
		||||
      }
 | 
			
		||||
      await organization_admin_model.addOrganizationAdministrator(req.body.person_id, req.body.organization_id);
 | 
			
		||||
      return res.status(200).json({success : true});
 | 
			
		||||
    }
 | 
			
		||||
    catch (error) {
 | 
			
		||||
      console.error('Error while adding organization admin: ' + error);
 | 
			
		||||
      res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  try {
 | 
			
		||||
    const isPersonAdmin = await organization_admin_model.isPersonAdmin(req.jwt.person_id, req.body.organization_id)
 | 
			
		||||
    // TOC/TOU
 | 
			
		||||
    if (!isPersonAdmin) {
 | 
			
		||||
      return res.status(401).json({ error: 'Forbidden' })
 | 
			
		||||
    }
 | 
			
		||||
    await organization_admin_model.addOrganizationAdministrator(req.body.person_id, req.body.organization_id)
 | 
			
		||||
    return res.status(200).json({ success: true })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error while adding organization admin: ' + error)
 | 
			
		||||
    res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
  /**
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   * DELETE Request
 | 
			
		||||
   * 
 | 
			
		||||
   *
 | 
			
		||||
   * Deletes a Person from the list of Administrators of an Organization.
 | 
			
		||||
   * The logged user can only remove themselves. If no more Administrators
 | 
			
		||||
   * are left, the Organization is removed.
 | 
			
		||||
   * 
 | 
			
		||||
   *
 | 
			
		||||
   * Required field(s): organization_id
 | 
			
		||||
   */
 | 
			
		||||
  async function removeOrganizationAdmin(req, res){
 | 
			
		||||
    
 | 
			
		||||
      // Ensure that the required fields are present before proceeding
 | 
			
		||||
      if (!req.body.organization_id) {
 | 
			
		||||
        return res.status(400).json({ error : "Invalid request"});
 | 
			
		||||
      }
 | 
			
		||||
  
 | 
			
		||||
      try{
 | 
			
		||||
        await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id);
 | 
			
		||||
        return res.status(200).json({success : true});
 | 
			
		||||
      }
 | 
			
		||||
      catch (error){
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        return res.status(500).json({ error: "Internal server error"});
 | 
			
		||||
      }
 | 
			
		||||
async function removeOrganizationAdmin (req, res) {
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.organization_id) {
 | 
			
		||||
    return res.status(400).json({ error: 'Invalid request' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id)
 | 
			
		||||
    return res.status(200).json({ success: true })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  addOrganizationAdmin,
 | 
			
		||||
  removeOrganizationAdmin
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,95 +2,90 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const knex = require('../utils/knex_config');
 | 
			
		||||
const knex = require('../utils/knex_config')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   * POST Request
 | 
			
		||||
   * 
 | 
			
		||||
   *
 | 
			
		||||
   * Creates a Post belonging to an organization
 | 
			
		||||
   *
 | 
			
		||||
   * Required field(s): organization_id, content
 | 
			
		||||
   * @returns the inserted Post 
 | 
			
		||||
   * @returns the inserted Post
 | 
			
		||||
   */
 | 
			
		||||
async function createOrganizationPost(req, res){
 | 
			
		||||
async function createOrganizationPost (req, res) {
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.organization_id || !req.body.content) {
 | 
			
		||||
    return res.status(400).json({ error: 'Invalid request' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // Ensure that the required fields are present before proceeding
 | 
			
		||||
    if (!req.body.organization_id || !req.body.content) {
 | 
			
		||||
      return res.status(400).json({ error : "Invalid request"});
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    try {
 | 
			
		||||
      // Check if the current user is a organization's administrator
 | 
			
		||||
      const isOrganizationAdmin = await knex('OrganizationAdministrator')
 | 
			
		||||
  try {
 | 
			
		||||
    // Check if the current user is a organization's administrator
 | 
			
		||||
    const isOrganizationAdmin = await knex('OrganizationAdministrator')
 | 
			
		||||
      .where('id_person', req.jwt.person_id)
 | 
			
		||||
      .where('id_organization', req.body.organization_id)
 | 
			
		||||
      .select('*')
 | 
			
		||||
      .first();
 | 
			
		||||
      
 | 
			
		||||
      // Non-exploitable TOC/TOU weakness
 | 
			
		||||
      // For more information https://softwareengineering.stackexchange.com/questions/451038/when-should-i-be-worried-of-time-of-check-time-of-use-vulnerabilities-during-dat
 | 
			
		||||
      if(!isOrganizationAdmin){
 | 
			
		||||
        return res.status(403).json({error : "Forbidden"});
 | 
			
		||||
      }
 | 
			
		||||
  
 | 
			
		||||
      const organizationPost = await knex('OrganizationPost')
 | 
			
		||||
      .first()
 | 
			
		||||
 | 
			
		||||
    // Non-exploitable TOC/TOU weakness
 | 
			
		||||
    // For more information https://softwareengineering.stackexchange.com/questions/451038/when-should-i-be-worried-of-time-of-check-time-of-use-vulnerabilities-during-dat
 | 
			
		||||
    if (!isOrganizationAdmin) {
 | 
			
		||||
      return res.status(403).json({ error: 'Forbidden' })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const organizationPost = await knex('OrganizationPost')
 | 
			
		||||
      .insert({
 | 
			
		||||
        organization_id: req.body.organization_id,
 | 
			
		||||
        content: req.body.content,
 | 
			
		||||
        original_author: req.jwt.person_id
 | 
			
		||||
      })
 | 
			
		||||
      .returning('*');
 | 
			
		||||
      return res.status(200).json(organizationPost[0]);
 | 
			
		||||
    } 
 | 
			
		||||
    catch (error) {
 | 
			
		||||
      console.log("Error while creating Organization Post: " + error);
 | 
			
		||||
      return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
    }
 | 
			
		||||
      .returning('*')
 | 
			
		||||
    return res.status(200).json(organizationPost[0])
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('Error while creating Organization Post: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * DELETE Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Deletes a Post belonging to an Organization, only if
 | 
			
		||||
 * the logged user is an administrator of that Organization.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none.
 | 
			
		||||
 */
 | 
			
		||||
async function deleteOrganizationPost(req, res){
 | 
			
		||||
async function deleteOrganizationPost (req, res) {
 | 
			
		||||
  const organizationPostIdToDelete = req.params.id
 | 
			
		||||
 | 
			
		||||
  const organizationPostIdToDelete = req.params.id;
 | 
			
		||||
 | 
			
		||||
  try{
 | 
			
		||||
  try {
 | 
			
		||||
    const isOrganizationAdmin = await knex('OrganizationPost')
 | 
			
		||||
      .join('OrganizationAdministrator', 'OrganizationPost.organization_id', 'OrganizationAdministrator.id_organization')
 | 
			
		||||
      .where('OrganizationPost.id', organizationPostIdToDelete)
 | 
			
		||||
      .where('OrganizationAdministrator.id_person', req.jwt.person_id)
 | 
			
		||||
      .select('*')
 | 
			
		||||
      .first();
 | 
			
		||||
      .first()
 | 
			
		||||
 | 
			
		||||
      // Unexploitable TOC/TOU
 | 
			
		||||
      if(isOrganizationAdmin){
 | 
			
		||||
        await knex('OrganizationPost')
 | 
			
		||||
          .where('id', organizationPostIdToDelete)
 | 
			
		||||
          .del();
 | 
			
		||||
        return res.status(200).json({success : true});
 | 
			
		||||
      }
 | 
			
		||||
      else{
 | 
			
		||||
        return res.status(401).json({error : "Forbidden"});
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.log(error);
 | 
			
		||||
    res.status(500).json({error : "Internal server error"});
 | 
			
		||||
    // Unexploitable TOC/TOU
 | 
			
		||||
    if (isOrganizationAdmin) {
 | 
			
		||||
      await knex('OrganizationPost')
 | 
			
		||||
        .where('id', organizationPostIdToDelete)
 | 
			
		||||
        .del()
 | 
			
		||||
      return res.status(200).json({ success: true })
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(401).json({ error: 'Forbidden' })
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log(error)
 | 
			
		||||
    res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -98,6 +93,6 @@ async function deleteOrganizationPost(req, res){
 | 
			
		||||
// means making a JavaScript function defined in one
 | 
			
		||||
// module available for use in another module.
 | 
			
		||||
module.exports = {
 | 
			
		||||
    createOrganizationPost,
 | 
			
		||||
    deleteOrganizationPost
 | 
			
		||||
};
 | 
			
		||||
  createOrganizationPost,
 | 
			
		||||
  deleteOrganizationPost
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,133 +2,124 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const organization_model = require('../models/organization_model');
 | 
			
		||||
const organization_model = require('../models/organization_model')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POST Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Creates an Organization and its Administrator.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): name
 | 
			
		||||
 *
 | 
			
		||||
 * @returns the inserted organization
 | 
			
		||||
 */
 | 
			
		||||
async function createOrganization(req, res){
 | 
			
		||||
 | 
			
		||||
async function createOrganization (req, res) {
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.name) {
 | 
			
		||||
    return res.status(400).json({ error : "Invalid request"});
 | 
			
		||||
    return res.status(400).json({ error: 'Invalid request' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try{
 | 
			
		||||
    const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring);
 | 
			
		||||
    await organization_model.insertOrganization(organization, req.jwt.person_id);
 | 
			
		||||
    return res.status(200).json({ Organization: organization });
 | 
			
		||||
  }
 | 
			
		||||
  catch (error){
 | 
			
		||||
    console.error('Error creating Organization:', error);
 | 
			
		||||
    res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  try {
 | 
			
		||||
    const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring)
 | 
			
		||||
    await organization_model.insertOrganization(organization, req.jwt.person_id)
 | 
			
		||||
    return res.status(200).json({ Organization: organization })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error creating Organization:', error)
 | 
			
		||||
    res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PUT Request
 | 
			
		||||
 * Updates an Organization's details
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none.
 | 
			
		||||
 */
 | 
			
		||||
async function updateOrganization(req, res){
 | 
			
		||||
async function updateOrganization (req, res) {
 | 
			
		||||
  const updateOrganization = {}
 | 
			
		||||
 | 
			
		||||
  const updateOrganization = {};
 | 
			
		||||
 | 
			
		||||
  if(req.body.name){
 | 
			
		||||
    updateOrganization.name = req.body.name;
 | 
			
		||||
  if (req.body.name) {
 | 
			
		||||
    updateOrganization.name = req.body.name
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.location){
 | 
			
		||||
    updateOrganization.location = req.body.location;
 | 
			
		||||
  if (req.body.location) {
 | 
			
		||||
    updateOrganization.location = req.body.location
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.description){
 | 
			
		||||
    updateOrganization.description = req.body.description;
 | 
			
		||||
  if (req.body.description) {
 | 
			
		||||
    updateOrganization.description = req.body.description
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.is_hiring){
 | 
			
		||||
    updateOrganization.is_hiring = req.body.is_hiring;
 | 
			
		||||
  if (req.body.is_hiring) {
 | 
			
		||||
    updateOrganization.is_hiring = req.body.is_hiring
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Object.keys(updateOrganization).length === 0) {
 | 
			
		||||
    return res.status(400).json({ error : "Bad request. No data to update"});
 | 
			
		||||
    return res.status(400).json({ error: 'Bad request. No data to update' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id);
 | 
			
		||||
    if(isUpdateSuccessful){
 | 
			
		||||
      return res.status(200).json({ success : "true"});
 | 
			
		||||
    const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id)
 | 
			
		||||
    if (isUpdateSuccessful) {
 | 
			
		||||
      return res.status(200).json({ success: 'true' })
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(404).json({ error: 'Organization either not found or insufficient permissions' })
 | 
			
		||||
    }
 | 
			
		||||
    else{
 | 
			
		||||
      return res.status(404).json({error : "Organization either not found or insufficient permissions"});
 | 
			
		||||
    }
 | 
			
		||||
  } 
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.log(error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log(error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * DELETE Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Deletes the specified organization if the logged user is
 | 
			
		||||
 * one of its administrator 
 | 
			
		||||
 * one of its administrator
 | 
			
		||||
 */
 | 
			
		||||
async function deleteOrganization(req, res){
 | 
			
		||||
async function deleteOrganization (req, res) {
 | 
			
		||||
  try {
 | 
			
		||||
    const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id);
 | 
			
		||||
    if(isDeleteSuccessful){
 | 
			
		||||
      return res.status(403).json({error: "Forbidden"});
 | 
			
		||||
    const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id)
 | 
			
		||||
    if (isDeleteSuccessful) {
 | 
			
		||||
      return res.status(403).json({ error: 'Forbidden' })
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(200).json({ success: true })
 | 
			
		||||
    }
 | 
			
		||||
    else{
 | 
			
		||||
      return res.status(200).json({success: true});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GET Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Obtains an organization by its identifier.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * @returns the organization.
 | 
			
		||||
 */
 | 
			
		||||
async function getOrganization(req, res){
 | 
			
		||||
async function getOrganization (req, res) {
 | 
			
		||||
  try {
 | 
			
		||||
    const organization = await organization_model.getOrganizationById(req.params.id);
 | 
			
		||||
    if(organization) {
 | 
			
		||||
      return res.status(200).json(organization);
 | 
			
		||||
    const organization = await organization_model.getOrganizationById(req.params.id)
 | 
			
		||||
    if (organization) {
 | 
			
		||||
      return res.status(200).json(organization)
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(404).json({ error: 'Not found' })
 | 
			
		||||
    }
 | 
			
		||||
    else{
 | 
			
		||||
      return res.status(404).json({error : "Not found"});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.error("Error retrieving an organization: " + error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error retrieving an organization: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -137,5 +128,4 @@ module.exports = {
 | 
			
		||||
  getOrganization,
 | 
			
		||||
  updateOrganization,
 | 
			
		||||
  deleteOrganization
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,102 +2,98 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const validator = require('../utils/validation');
 | 
			
		||||
const knex = require('../utils/knex_config');
 | 
			
		||||
const jwt_utils = require('../utils/jwt_utils');
 | 
			
		||||
const bcrypt = require('bcrypt');
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const person_model = require('../models/person_model');
 | 
			
		||||
const validator = require('../utils/validation')
 | 
			
		||||
const knex = require('../utils/knex_config')
 | 
			
		||||
const jwt_utils = require('../utils/jwt_utils')
 | 
			
		||||
const bcrypt = require('bcrypt')
 | 
			
		||||
const crypto = require('crypto')
 | 
			
		||||
const person_model = require('../models/person_model')
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POST Request
 | 
			
		||||
 *
 | 
			
		||||
 * Registers a Person
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): name, email (valid ISO standard), password
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * @returns The activationlink identifier
 | 
			
		||||
 */
 | 
			
		||||
async function registerPerson(req, res){
 | 
			
		||||
  
 | 
			
		||||
async function registerPerson (req, res) {
 | 
			
		||||
  // Does this server allow users to register?
 | 
			
		||||
  if (process.env.ALLOW_USER_REGISTRATION === 'false'){
 | 
			
		||||
    return res.status(403).json({error : "Users cannot register on this server"});
 | 
			
		||||
  if (process.env.ALLOW_USER_REGISTRATION === 'false') {
 | 
			
		||||
    return res.status(403).json({ error: 'Users cannot register on this server' })
 | 
			
		||||
  }
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.display_name || !req.body.email || !req.body.password) {
 | 
			
		||||
    return res.status(400).json({ error : "Some or all required fields are missing"});
 | 
			
		||||
    return res.status(400).json({ error: 'Some or all required fields are missing' })
 | 
			
		||||
  }
 | 
			
		||||
  if(!validator.validateEmail(req.body.email)){
 | 
			
		||||
    return res.status(400).json({ error : "The email is not in a valid format"});
 | 
			
		||||
  if (!validator.validateEmail(req.body.email)) {
 | 
			
		||||
    return res.status(400).json({ error: 'The email is not in a valid format' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Generate activation link token
 | 
			
		||||
  const activationLink = crypto.randomBytes(16).toString('hex');
 | 
			
		||||
  const activationLink = crypto.randomBytes(16).toString('hex')
 | 
			
		||||
  // Hash provided password
 | 
			
		||||
  const hashPasswordPromise = bcrypt.hash(req.body.password, 10);
 | 
			
		||||
  const hashPasswordPromise = bcrypt.hash(req.body.password, 10)
 | 
			
		||||
 | 
			
		||||
  try{
 | 
			
		||||
  try {
 | 
			
		||||
    // Check whether e-mail exists already (enforced by database constraints)
 | 
			
		||||
    const existingUser = await person_model.getPersonByEmail(req.body.email);
 | 
			
		||||
    if(existingUser){
 | 
			
		||||
      return res.status(409).json({ error: "E-mail already in use" });
 | 
			
		||||
    const existingUser = await person_model.getPersonByEmail(req.body.email)
 | 
			
		||||
    if (existingUser) {
 | 
			
		||||
      return res.status(409).json({ error: 'E-mail already in use' })
 | 
			
		||||
    }
 | 
			
		||||
    const personToInsert = person_model.person(
 | 
			
		||||
      req.body.email, 
 | 
			
		||||
      req.body.email,
 | 
			
		||||
      await hashPasswordPromise,
 | 
			
		||||
      req.body.display_name,
 | 
			
		||||
      req.body.date_of_birth,
 | 
			
		||||
      req.body.available,
 | 
			
		||||
      true,
 | 
			
		||||
      req.body.place_of_living);
 | 
			
		||||
    await person_model.registerPerson(personToInsert, activationLink);
 | 
			
		||||
    return res.status(200).json({ activationLink: activationLink });
 | 
			
		||||
  }
 | 
			
		||||
  catch (error){
 | 
			
		||||
    console.error('Error registering person:', error);
 | 
			
		||||
    res.status(500).json({error : "Internal server error"});
 | 
			
		||||
      req.body.place_of_living)
 | 
			
		||||
    await person_model.registerPerson(personToInsert, activationLink)
 | 
			
		||||
    return res.status(200).json({ activationLink })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error registering person:', error)
 | 
			
		||||
    res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POST Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Creates a token if the specified email
 | 
			
		||||
 * and password are valid.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): email, password
 | 
			
		||||
 *
 | 
			
		||||
 * @returns The token
 | 
			
		||||
 */
 | 
			
		||||
async function login(req, res){
 | 
			
		||||
 | 
			
		||||
async function login (req, res) {
 | 
			
		||||
  // Ensure that the required fields are present before proceeding
 | 
			
		||||
  if (!req.body.email || !req.body.password) {
 | 
			
		||||
    return res.status(400).json({error : "Invalid request"});
 | 
			
		||||
    return res.status(400).json({ error: 'Invalid request' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try{
 | 
			
		||||
    const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password);
 | 
			
		||||
    if (person){
 | 
			
		||||
      const token = jwt_utils.generateToken(person.id);
 | 
			
		||||
      res.status(200).json({token: token });
 | 
			
		||||
  try {
 | 
			
		||||
    const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password)
 | 
			
		||||
    if (person) {
 | 
			
		||||
      const token = jwt_utils.generateToken(person.id)
 | 
			
		||||
      res.status(200).json({ token })
 | 
			
		||||
    } else {
 | 
			
		||||
      res.status(401).json({ error: 'Unauthorized' })
 | 
			
		||||
    }
 | 
			
		||||
    else{ 
 | 
			
		||||
      res.status(401).json({error : "Unauthorized"});
 | 
			
		||||
    }
 | 
			
		||||
  } catch(error){
 | 
			
		||||
    console.error('Error logging in: ', error);
 | 
			
		||||
    res.status(500).json({error : "Internal server error"});
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('Error logging in: ', error)
 | 
			
		||||
    res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -105,138 +101,131 @@ async function login(req, res){
 | 
			
		||||
 * Obtain a Person's details if the
 | 
			
		||||
 * Person to retrieve is either myself or an
 | 
			
		||||
 * enabled Person.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none
 | 
			
		||||
 *
 | 
			
		||||
 * @returns The Person
 | 
			
		||||
 */
 | 
			
		||||
async function getPerson(req, res){
 | 
			
		||||
async function getPerson (req, res) {
 | 
			
		||||
  try {
 | 
			
		||||
    const person = await person_model.getPersonById(req.params.id);
 | 
			
		||||
    if(person){
 | 
			
		||||
    const person = await person_model.getPersonById(req.params.id)
 | 
			
		||||
    if (person) {
 | 
			
		||||
      // I am retrieving either myself or an enabled user
 | 
			
		||||
      if(person.id == req.jwt.person_id || person.enabled){
 | 
			
		||||
        delete person['password']; // remove password field for security reasons
 | 
			
		||||
        return res.status(200).send(person);
 | 
			
		||||
      if (person.id == req.jwt.person_id || person.enabled) {
 | 
			
		||||
        delete person.password // remove password field for security reasons
 | 
			
		||||
        return res.status(200).send(person)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return res.status(404).json({error: "Not found"});
 | 
			
		||||
  }
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.log("Error while getting person: " + error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
    return res.status(404).json({ error: 'Not found' })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('Error while getting person: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * GET Request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Get myself, from the JWT token
 | 
			
		||||
 *
 | 
			
		||||
 * @returns Person's details
 | 
			
		||||
 */
 | 
			
		||||
async function getMyself(req, res){
 | 
			
		||||
  try{
 | 
			
		||||
    const person = await person_model.getPersonById(req.jwt.person_id);
 | 
			
		||||
    if(person){
 | 
			
		||||
      delete person['password'];
 | 
			
		||||
      return res.status(200).send(person);
 | 
			
		||||
async function getMyself (req, res) {
 | 
			
		||||
  try {
 | 
			
		||||
    const person = await person_model.getPersonById(req.jwt.person_id)
 | 
			
		||||
    if (person) {
 | 
			
		||||
      delete person.password
 | 
			
		||||
      return res.status(200).send(person)
 | 
			
		||||
    }
 | 
			
		||||
    return res.status(404).json({error: "Not found"});
 | 
			
		||||
  }
 | 
			
		||||
  catch (error){
 | 
			
		||||
    console.log("Error while getting myself: " + error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
    return res.status(404).json({ error: 'Not found' })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('Error while getting myself: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PUT request
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Updates a Person's details. If some details are
 | 
			
		||||
 * not present, they shall be ignored.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none. Both old_password and
 | 
			
		||||
 * new_password if updating the password.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
async function updatePerson(req, res){
 | 
			
		||||
  
 | 
			
		||||
  if (req.jwt.person_id != req.params.id){
 | 
			
		||||
    return res.status(403).json({ error : "Forbidden"});
 | 
			
		||||
async function updatePerson (req, res) {
 | 
			
		||||
  if (req.jwt.person_id != req.params.id) {
 | 
			
		||||
    return res.status(403).json({ error: 'Forbidden' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const updatePerson = {};
 | 
			
		||||
  const updatePerson = {}
 | 
			
		||||
 | 
			
		||||
  if(req.body.display_name){
 | 
			
		||||
    updatePerson.display_name = req.body.display_name;
 | 
			
		||||
  if (req.body.display_name) {
 | 
			
		||||
    updatePerson.display_name = req.body.display_name
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.date_of_birth){
 | 
			
		||||
    if(validator.isPostgresDateFormatValid(req.body.date_of_birth)){
 | 
			
		||||
      updatePerson.date_of_birth = req.body.date_of_birth;
 | 
			
		||||
    }
 | 
			
		||||
    else{
 | 
			
		||||
      return res.status(400).json({ error : "Date of birth format not valid. Please specify a YYYY-MM-DD date"});
 | 
			
		||||
  if (req.body.date_of_birth) {
 | 
			
		||||
    if (validator.isPostgresDateFormatValid(req.body.date_of_birth)) {
 | 
			
		||||
      updatePerson.date_of_birth = req.body.date_of_birth
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(400).json({ error: 'Date of birth format not valid. Please specify a YYYY-MM-DD date' })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.available){
 | 
			
		||||
    updatePerson.available = req.body.available;
 | 
			
		||||
  if (req.body.available) {
 | 
			
		||||
    updatePerson.available = req.body.available
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(req.body.place_of_living){
 | 
			
		||||
    updatePerson.place_of_living = req.body.place_of_living;
 | 
			
		||||
  if (req.body.place_of_living) {
 | 
			
		||||
    updatePerson.place_of_living = req.body.place_of_living
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
  // If we are tying to change password, the old password must be provided
 | 
			
		||||
  if(req.body.old_password && req.body.new_password){
 | 
			
		||||
  if (req.body.old_password && req.body.new_password) {
 | 
			
		||||
    const user = await knex('Person')
 | 
			
		||||
      .select('password')
 | 
			
		||||
      .where({ id: req.jwt.person_id })
 | 
			
		||||
      .first();
 | 
			
		||||
      const passwordMatches = await bcrypt.compare(req.body.old_password, user.password);
 | 
			
		||||
      if(passwordMatches){
 | 
			
		||||
        updatePerson.password = await bcrypt.hash(req.body.new_password, 10);
 | 
			
		||||
      }
 | 
			
		||||
      else{
 | 
			
		||||
        return res.status(401).json({ error : "Password verification failed"});
 | 
			
		||||
      }
 | 
			
		||||
      .first()
 | 
			
		||||
    const passwordMatches = await bcrypt.compare(req.body.old_password, user.password)
 | 
			
		||||
    if (passwordMatches) {
 | 
			
		||||
      updatePerson.password = await bcrypt.hash(req.body.new_password, 10)
 | 
			
		||||
    } else {
 | 
			
		||||
      return res.status(401).json({ error: 'Password verification failed' })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (Object.keys(updatePerson).length === 0) {
 | 
			
		||||
    return res.status(400).json({ error : "Bad request. No data to update"});
 | 
			
		||||
    return res.status(400).json({ error: 'Bad request. No data to update' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    await person_model.updatePerson(updatePerson, req.params.id);
 | 
			
		||||
    return res.status(200).json({ success : "true"});
 | 
			
		||||
  }
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.log("Error while updating a Person: " + error);
 | 
			
		||||
    return res.status(500).json({ error : "Internal server error"});
 | 
			
		||||
    await person_model.updatePerson(updatePerson, req.params.id)
 | 
			
		||||
    return res.status(200).json({ success: 'true' })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('Error while updating a Person: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GET Request
 | 
			
		||||
 * 
 | 
			
		||||
 * Deletes a Person. An user can only delete 
 | 
			
		||||
 *
 | 
			
		||||
 * Deletes a Person. An user can only delete
 | 
			
		||||
 * themselves.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 * Required field(s): none
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
async function deletePerson(req, res) {
 | 
			
		||||
async function deletePerson (req, res) {
 | 
			
		||||
  // TODO: Delete Organization if this user was its only administrator
 | 
			
		||||
  try {
 | 
			
		||||
    await person_model.deletePerson(req.jwt.person_id);
 | 
			
		||||
    return res.status(200).json({success: true});
 | 
			
		||||
  } 
 | 
			
		||||
  catch (error) {
 | 
			
		||||
    console.log("Error deleting a Person: " + error);
 | 
			
		||||
    return res.status(500).json({error : "Internal server error"});
 | 
			
		||||
    await person_model.deletePerson(req.jwt.person_id)
 | 
			
		||||
    return res.status(200).json({ success: true })
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.log('Error deleting a Person: ' + error)
 | 
			
		||||
    return res.status(500).json({ error: 'Internal server error' })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -244,10 +233,10 @@ async function deletePerson(req, res) {
 | 
			
		||||
// means making a JavaScript function defined in one
 | 
			
		||||
// module available for use in another module.
 | 
			
		||||
module.exports = {
 | 
			
		||||
    registerPerson,
 | 
			
		||||
    login,
 | 
			
		||||
    getPerson,
 | 
			
		||||
    getMyself,
 | 
			
		||||
    updatePerson,
 | 
			
		||||
    deletePerson
 | 
			
		||||
};
 | 
			
		||||
  registerPerson,
 | 
			
		||||
  login,
 | 
			
		||||
  getPerson,
 | 
			
		||||
  getMyself,
 | 
			
		||||
  updatePerson,
 | 
			
		||||
  deletePerson
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,50 +2,50 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const jwt = require('jsonwebtoken');
 | 
			
		||||
const jwt = require('jsonwebtoken')
 | 
			
		||||
 | 
			
		||||
function generateToken(person_id) {
 | 
			
		||||
    // The payload the JWT will carry within itself
 | 
			
		||||
    const payload = {
 | 
			
		||||
      person_id: person_id
 | 
			
		||||
    };
 | 
			
		||||
  
 | 
			
		||||
    const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, { 
 | 
			
		||||
      expiresIn: '8h' 
 | 
			
		||||
    });
 | 
			
		||||
    return token;
 | 
			
		||||
function generateToken (person_id) {
 | 
			
		||||
  // The payload the JWT will carry within itself
 | 
			
		||||
  const payload = {
 | 
			
		||||
    person_id
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // Middlware
 | 
			
		||||
  function verifyToken(req, res, next) {
 | 
			
		||||
    const token = req.headers.authorization;
 | 
			
		||||
  
 | 
			
		||||
    if (!token) {
 | 
			
		||||
      return res.status(401).send({error : 'No token provided'});
 | 
			
		||||
 | 
			
		||||
  const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, {
 | 
			
		||||
    expiresIn: '8h'
 | 
			
		||||
  })
 | 
			
		||||
  return token
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Middlware
 | 
			
		||||
function verifyToken (req, res, next) {
 | 
			
		||||
  const token = req.headers.authorization
 | 
			
		||||
 | 
			
		||||
  if (!token) {
 | 
			
		||||
    return res.status(401).send({ error: 'No token provided' })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  jwt.verify(token, process.env.JWT_SECRET_KEY, (err, decoded) => {
 | 
			
		||||
    if (err) {
 | 
			
		||||
      return res.status(401).send({ error: 'Failed to authenticate token' })
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    jwt.verify(token, process.env.JWT_SECRET_KEY, (err, decoded) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        return res.status(401).send({error : 'Failed to authenticate token'});
 | 
			
		||||
      }
 | 
			
		||||
  
 | 
			
		||||
      // If the token is valid, store the decoded data in the request object
 | 
			
		||||
      // req.jwt will contain the payload created in generateToken
 | 
			
		||||
      req.jwt = decoded;
 | 
			
		||||
      next();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  module.exports = {
 | 
			
		||||
    generateToken,
 | 
			
		||||
    verifyToken
 | 
			
		||||
};
 | 
			
		||||
    // If the token is valid, store the decoded data in the request object
 | 
			
		||||
    // req.jwt will contain the payload created in generateToken
 | 
			
		||||
    req.jwt = decoded
 | 
			
		||||
    next()
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  generateToken,
 | 
			
		||||
  verifyToken
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,24 +2,24 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const knexInstance = require('knex')({
 | 
			
		||||
    client: 'pg',
 | 
			
		||||
    connection: {
 | 
			
		||||
      host: process.env.POSTGRES_SERVER,
 | 
			
		||||
      user: process.env.POSTGRES_USERNAME,
 | 
			
		||||
      password: process.env.POSTGRES_PASSWORD,
 | 
			
		||||
      port: process.env.POSTGRES_PORT,
 | 
			
		||||
      database: 'Blink'
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  client: 'pg',
 | 
			
		||||
  connection: {
 | 
			
		||||
    host: process.env.POSTGRES_SERVER,
 | 
			
		||||
    user: process.env.POSTGRES_USERNAME,
 | 
			
		||||
    password: process.env.POSTGRES_PASSWORD,
 | 
			
		||||
    port: process.env.POSTGRES_PORT,
 | 
			
		||||
    database: 'Blink'
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
  module.exports = knexInstance;
 | 
			
		||||
module.exports = knexInstance
 | 
			
		||||
 
 | 
			
		||||
@@ -2,37 +2,37 @@
 | 
			
		||||
    This code is part of Blink
 | 
			
		||||
    licensed under GPLv3
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | 
			
		||||
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
			
		||||
    IN THE SOFTWARE.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks whether an e-mail is in a valid format
 | 
			
		||||
 * @param {*} email email to validate 
 | 
			
		||||
 * @param {*} email email to validate
 | 
			
		||||
 * @returns true or false
 | 
			
		||||
 */
 | 
			
		||||
function validateEmail(email) {
 | 
			
		||||
    const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
 | 
			
		||||
    return regex.test(email);
 | 
			
		||||
function validateEmail (email) {
 | 
			
		||||
  const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/
 | 
			
		||||
  return regex.test(email)
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks whether a date is in a correct Postgres
 | 
			
		||||
 * format (YYYY-MM-DD)
 | 
			
		||||
 * @param {*} dateString the date to validate 
 | 
			
		||||
 * @param {*} dateString the date to validate
 | 
			
		||||
 * @returns true or false
 | 
			
		||||
 */
 | 
			
		||||
function isPostgresDateFormatValid(dateString) {
 | 
			
		||||
    const regex = /^\d{4}-\d{2}-\d{2}$/;
 | 
			
		||||
    return regex.test(dateString);
 | 
			
		||||
function isPostgresDateFormatValid (dateString) {
 | 
			
		||||
  const regex = /^\d{4}-\d{2}-\d{2}$/
 | 
			
		||||
  return regex.test(dateString)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    validateEmail,
 | 
			
		||||
    isPostgresDateFormatValid
 | 
			
		||||
};
 | 
			
		||||
  validateEmail,
 | 
			
		||||
  isPostgresDateFormatValid
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,30 @@
 | 
			
		||||
// Run me with "npm test"
 | 
			
		||||
 | 
			
		||||
const request = require('supertest');
 | 
			
		||||
const app = require('../src/app');
 | 
			
		||||
require('dotenv').config({ path: '../src/.env' });
 | 
			
		||||
const request = require('supertest')
 | 
			
		||||
const app = require('../src/app')
 | 
			
		||||
require('dotenv').config({ path: '../src/.env' })
 | 
			
		||||
 | 
			
		||||
describe('Person Tests', () => {
 | 
			
		||||
  test('Correct registration', async () => {
 | 
			
		||||
    const response = await request(app)
 | 
			
		||||
        .post('/api/register')
 | 
			
		||||
        .send({
 | 
			
		||||
            email : "johntestdoe@mail.org",
 | 
			
		||||
            password : "password",
 | 
			
		||||
            display_name : "John Doe"
 | 
			
		||||
        })
 | 
			
		||||
    expect(response.status).toBe(200);
 | 
			
		||||
    expect(response.body).toEqual({ activationLink: expect.any(String) });
 | 
			
		||||
  });
 | 
			
		||||
      .post('/api/register')
 | 
			
		||||
      .send({
 | 
			
		||||
        email: 'johntestdoe@mail.org',
 | 
			
		||||
        password: 'password',
 | 
			
		||||
        display_name: 'John Doe'
 | 
			
		||||
      })
 | 
			
		||||
    expect(response.status).toBe(200)
 | 
			
		||||
    expect(response.body).toEqual({ activationLink: expect.any(String) })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  test('Incorrect registration', async () => {
 | 
			
		||||
    const response = await request(app)
 | 
			
		||||
        .post('/api/register')
 | 
			
		||||
        .send({
 | 
			
		||||
            email : "this is not an email",
 | 
			
		||||
            password : "password",
 | 
			
		||||
            display_name : "John Doe"
 | 
			
		||||
        })
 | 
			
		||||
    expect(response.status).toBe(400);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
      .post('/api/register')
 | 
			
		||||
      .send({
 | 
			
		||||
        email: 'this is not an email',
 | 
			
		||||
        password: 'password',
 | 
			
		||||
        display_name: 'John Doe'
 | 
			
		||||
      })
 | 
			
		||||
    expect(response.status).toBe(400)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
const apiUrl = "http://localhost:3000/blinkapi";
 | 
			
		||||
const apiUrl = 'http://localhost:3000/blinkapi'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user