HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/RImmers2/portal.photomenu.nl/wwwroot/controllers/restaurants.js
exports.install = function () {
  F.route('/restaurants', restraurantsIndex, ['get', 'authorize']);
  F.route('/restaurants/edit/{id}', restraurantsEdit, ['get', 'authorize']);
  F.route('/restaurants/edit/{id}', restraurantsPost, ['+xhr', 'upload', 'post']);
  F.route('/restaurants/edit/{id}/delete-image/{index}', deleteImage, ['get']);

  F.route('/restaurants/delete/{id}', restraurantsDelete, ['get', 'authorize']);
};

const path = require('path');
const Promise = require("bluebird");
const uuidV4 = require('uuid/v4');
const phoneFormatter = require('phone');
const validator = require('validator');
const gm = require('gm').subClass({
  imageMagick: false
});

function sendEmail(fromaddress,toaddress,txtsubject,txthtml,bodytext,filePath) {
  var nodemailer = require('nodemailer');
  var smtpTransport = require('nodemailer-smtp-transport');
  var transporter = nodemailer.createTransport(smtpTransport({
    host: 'localhost',
    port: 25   
  }));
  transporter.sendMail({
    from: fromaddress,
    to: toaddress,
    subject: txtsubject,
    html: txthtml,
    text: bodytext,
    //   attachments: [
    //    {   // utf-8 string as an attachment
    //       path: filePath
    //    }]
  }).catch(err => {
    console.log(err);
  });
}

function deleteImage(id, index) {
  const params = {};
  const self = this;
  F.model('restaurant').load(id).then(function (restaurant) {
    params.id = id;
    params.restaurant = restaurant;
    if (params.restaurant.images.length === 1) {
      params.error = true;
      params.errorMessage = "At least one image is required."
      self.layout('/layouts/protected');
      self.view('/restaurants/edit', params);
    } else {
      const result = [];
      params.restaurant.images.forEach((url, i) => {
        if (i !== +index) {
          result.push(url);
        }
      })
      params.restaurant.images = result;
      return F.model('restaurant').edit(params).then(function () {
        self.res.redirect(`/restaurants/edit/${id}`);
      })
    }

  }).catch(err => console.log(err));
}

function restraurantsIndex() {
  var self = this;
  var params = {};
  F.model('restaurant').list().then(function (snapshot) {
    params.list = {};
    if (self.repository.type === 'restaurant') {
      let item = snapshot.val()[self.repository.currentRestaurant];
      item.key = self.repository.currentRestaurant;
      params.list = [item];
    } else {
      let sorted = [];
      snapshot.forEach(r => {
        let item = r.val();
        item.key = r.key;
        sorted.push(item);
      })
     
	  
//	 params.list = sorted.sort((i1, i2) => {
//		  if (i1.Name.toLowerCase() < i2.Name.toLowerCase()) return -1;
//          if (i1.Name.toLowerCase() === i2.Name.toLowerCase()) return 0;
//          if (i1.Name.toLowerCase() > i2.Name.toLowerCase()) return 1;
//      });
//	   params.list = sorted.sort((i1, i2) => {
//		if (i1.Inactive == 0) return -1;
//		if (i1.Inactive == 1) return 1;	
//	  });
//    
    params.list = sorted.sort((i1, i2) => i1.Inactive - i2.Inactive || i1.Name.toLowerCase().localeCompare(i2.Name.toLowerCase()));
    }
    	
    self.layout('/layouts/protected');
    self.view('/restaurants/index', params);
  });
};

function restraurantsEdit(id) {
  var self = this;
  var params = {};

  console.log('self.repository.currentRestaurant', self.repository.currentRestaurant)
  // Check if allowed access.
  if (self.repository.currentRestaurant && self.repository.currentRestaurant !== id && self.repository.type !== 'admin') {
    self.res.redirect('/');
  }

  self.layout('/layouts/protected');
  params.id = id;
  params.restaurant = false;
  if (id === 'new') {
    self.view('/restaurants/edit', params);
  } else {
    F.model('restaurant').load(id).then(function (restaurant) {
      params.restaurant = restaurant;
      self.view('/restaurants/edit', params);
    }).catch(err => console.log(err));
  }
};



function restraurantsPost(id) {
  var self = this;
  var params = {};
  params.restaurant = self.body;
  params.id = id;

  // Format phone number.
  const [formattedPhoneNumber] = phoneFormatter(self.body['Phone']);
  self.body['Phone'] = formattedPhoneNumber || self.body['Phone'];
  self.body['Phone'] = (self.body['Phone'].startsWith('+')) ? self.body['Phone'] : '+' + self.body['Phone'];

  // Format data.
  self.body['Credits'] = parseInt(self.body['Credits']) || null;
  self.body['Inactive'] = self.body['Inactive'] == 'on' ? false : true;
  self.body['Subscription'] =  self.body['Subscription'] == 'none-selected' ? null : self.body['Subscription']; 
  self.body['SubscriptionDate'] = self.body['SubscriptionDate'] || '';
  self.body['hasActiveDishes'] = self.body['hasActiveDishes'] == 'on' ? true : false;
  self.body['Disable share emails'] = self.body['Disable share emails'] == 'on' ? true : false;
  self.body['Number of times shown android'] = parseInt(self.body['Number of times shown android']) || null;
  self.body['Number of times shown iOS'] = parseInt(self.body['Number of times shown iOS']) || null;
   
  // Format url.
  self.body['Website'] = self.body['Website'] || '';
  self.body['Website'] = 'http://' + self.body['Website'].replace('http://', '').replace('https://', '');
  params.restaurant['Opening hours per day'] = [];
  params.restaurant['Opening hours per day'][0] = self.body['MON'] || '';
  params.restaurant['Opening hours per day'][1] = self.body['TUE'] || '';
  params.restaurant['Opening hours per day'][2] = self.body['WED'] || '';
  params.restaurant['Opening hours per day'][3] = self.body['THU'] || '';
  params.restaurant['Opening hours per day'][4] = self.body['FRI'] || '';
  params.restaurant['Opening hours per day'][5] = self.body['SAT'] || '';
  params.restaurant['Opening hours per day'][6] = self.body['SUN'] || '';

  params.restaurant['Opening hours per day ENG'] = [];
  params.restaurant['Opening hours per day ENG'][0] = self.body['MON-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][1] = self.body['TUE-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][2] = self.body['WED-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][3] = self.body['THU-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][4] = self.body['FRI-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][5] = self.body['SAT-ENG'] || '';
  params.restaurant['Opening hours per day ENG'][6] = self.body['SUN-ENG'] || '';

  delete params.restaurant['MON'];
  delete params.restaurant['TUE'];
  delete params.restaurant['WED'];
  delete params.restaurant['THU'];
  delete params.restaurant['FRI'];
  delete params.restaurant['SAT'];
  delete params.restaurant['SUN'];

  delete params.restaurant['MON-ENG'];
  delete params.restaurant['TUE-ENG'];
  delete params.restaurant['WED-ENG'];
  delete params.restaurant['THU-ENG'];
  delete params.restaurant['FRI-ENG'];
  delete params.restaurant['SAT-ENG'];
  delete params.restaurant['SUN-ENG'];

  // Check if both tumb and at least one image are added.
  let hasThumb = false;
  let hasImage = false;
  let photoToLarge = false;
  self.files.forEach(file => {
    if (id === 'new') {
      if (file.name === 'thumbnail') {
        hasThumb = true;
      } else {
        hasImage = true;
      }
    }
    // Validate photo size and resolution.
    if (file.length > 10000000) {
      params.error = true;
      params.errorMessage = `"${file.filename}" is to large.`
    }
    const exp = new RegExp(/\.(gif|jpg|jpeg|png|GIF|JPG|JPEG|PNG)$/);
    if (!exp.test(file.filename)) {
      params.error = true;
      params.errorMessage = `"${file.filename}" is invalid type.`
    }
  });
  if (id === 'new') {
    if (!hasThumb) {
      params.error = true;
      params.errorMessage = "Thumbnail image is required."
    }
    if (!hasImage) {
      params.error = true;
      params.errorMessage = "At least one image is required."
    }
  }

  // Input validations.
  if (self.repository.type === 'admin') {
    // Format coords.
    self.body['longitude'] = parseFloat(self.body['longitude']);
    self.body['latitude'] = parseFloat(self.body['latitude']);

    if (!self.body['longitude'] && self.body['longitude'] !== undefined) {
      params.error = true;
      params.errorMessage = 'Invalid "longitude" value.'
    }
    if (!self.body['latitude'] && self.body['latitude'] !== undefined) {
      params.error = true;
      params.errorMessage = 'Invalid "latitude" value.'
    }
    if (!self.body['Number of times shown android']) {
      params.error = true;
      params.errorMessage = 'Invalid "Number of times shown android" value.'
    }
    if (!self.body['Number of times shown iOS']) {
      params.error = true;
      params.errorMessage = 'Invalid "Number of times shown iOS" value.'
    }
  }
  if (!self.body['Lunch start'] && self.body['Lunch finish']) {
    params.error = true;
    params.errorMessage = '"Lunch start" value is required.'
  }
  if (self.body['Lunch start'] && !self.body['Lunch finish']) {
    params.error = true;
    params.errorMessage = '"Lunch finish" value is required.'
  }
  //if (!validator.isEmail(self.body['E-mail']) || !validator.isLength(self.body['E-mail'], {  
  if (!validator.isLength(self.body['E-mail'], {  
      min: 1,
      max: 40
    })) {
    params.error = true;
    params.errorMessage = 'Invalid "E-mail" value.'
  }
  if (!validator.isLength(self.body['Address'] || '', {
      min: 1,
      max: 35
    })) {
    params.error = true;
    params.errorMessage = '"Address" value can have max 35 characters.';
    self.body['Address'] = self.body['Address'] || '';
    if (self.body['Address'].length < 1) {
      params.errorMessage = '"Address" value is required.'
    }
  }
  if (!validator.isLength(self.body['Country'] || '', {
      min: 1,
      max: 25
    })) {
    params.error = true;
    params.errorMessage = '"Country" value can have max 25 characters.';
    self.body['Country'] = self.body['Country'] || '';
    if (self.body['Country'].length < 1) {
      params.errorMessage = '"Country" value is required.'
    }
  }
  if (!validator.isLength(self.body['City'] || '', {
      min: 1,
      max: 28
    })) {
    params.error = true;
    params.errorMessage = '"City" value can have max 28 characters.';
    self.body['City'] = self.body['City'] || '';
    if (self.body['City'].length < 1) {
      params.errorMessage = '"City" value is required.'
    }
  }
  if (!validator.isLength(self.body['Type of restaurant'] || '', {
      min: 1,
      max: 40
    })) {
    params.error = true;
    params.errorMessage = '"Type of restaurant" value can have max 40 characters.';
    self.body['Type of restaurant'] = self.body['Type of restaurant'] || '';
    if (self.body['Type of restaurant'].length < 1) {
      params.errorMessage = '"Type of restaurant" value is required.'
    }
  }
  if (!validator.isLength(self.body['Description'] || '', {
      min: 1,
      max: 400
    })) {
    params.error = true;
    params.errorMessage = '"Description" value can have max 400 characters.';
    self.body['Description'] = self.body['Description'] || '';
    if (self.body['Description'].length < 1) {
      params.errorMessage = '"Description" value is required.'
    }
  }
  if (!validator.isLength(self.body['Description ENG'] || '', {
      min: 0,
      max: 400
    })) {
    params.error = true;
    params.errorMessage = '"Description ENG" value can have max 400 characters.'
  }
  if (!validator.isLength(self.body['Opening hours'] || '', {
      min: 1,
      max: 70
    })) {
    params.error = true;
    params.errorMessage = '"Opening hours" value can have max 70 characters.';
    self.body['Opening hours'] = self.body['Opening hours'] || '';
    if (self.body['Opening hours'].length < 1) {
      params.errorMessage = '"Opening hours" value is required.'
    }
  }
  if (!validator.isLength(self.body['Opening hours ENG'] || '', {
      min: 0,
      max: 70
    })) {
    params.error = true;
    params.errorMessage = '"Opening hours ENG" value can have max 70 characters.'
  }
  if (self.repository.type === 'admin') {
    if (!self.body['Credits']) {
      params.error = true;
      params.errorMessage = '"Credits" value is required.'
    }
  }
  if (!validator.isLength(self.body['Name'] || '', {
      min: 1,
      max: 25
    })) {
    params.error = true;
    params.errorMessage = '"Name" value can have max 25 characters.';
    self.body['Name'] = self.body['Name'] || '';
    if (self.body['Name'].length < 1) {
      params.errorMessage = '"Name" value is required.'
    }
  }

  if (!validator.isLength(self.body['Phone'] || '', {
      min: 1,
      max: 15
    })) {
    params.error = true;
    params.errorMessage = '"Phone" value can have max 15 characters.'
  }
  const phoneReg = /^\+[0-9]*$/;
  if (!phoneReg.test(self.body['Phone'])) {
    params.error = true;
    params.errorMessage = '"Phone" value is invalid';
  }
  if (!validator.isLength(self.body['Postcode'] || '', {
      min: 1,
      max: 10
    })) {
    params.error = true;
    params.errorMessage = '"Postcode" value can have max 10 characters.';
    self.body['Postcode'] = self.body['Postcode'] || '';
    if (self.body['Postcode'].length < 1) {
      params.errorMessage = '"Postcode" value is required.'
    }
  }
  const isValidURL = validator.isURL(self.body['Website'] || '');
  if (!isValidURL || !validator.isLength(self.body['Website'], {
      min: 0,
      max: 40
    })) {
    params.error = true;
    params.errorMessage = isValidURL ? '"Website" value can have max 40 characters.' : '"Website" value is invalid';
  }

  if (params.error) {
    self.layout('/layouts/protected');
    F.model('restaurant').load(id).then(function (old) {
      params.restaurant.images = old.images;
      params.restaurant.thumbnail = old.thumbnail;
      if (self.repository.type === 'restaurant') {
        params.restaurant.Credits = old.Credits;
        params.restaurant.longitude = old.longitude;
        params.restaurant.latitude = old.latitude;
      }
      self.view('/restaurants/edit', params);
    }).catch(err => self.view('/restaurants/edit', params));
  } else {
    // email edit restaurant
    var strMailBody = 'Restaurant: ' + self.body['Name'] + '\nInActive: ' + self.body['Inactive'] + '\nDescription: ' + self.body['Description'];
    var strHTMLMailBody = 'Restaurant: ' + self.body['Name'] + '<br/>InActive: ' + self.body['Inactive'] + '<br/>Description:' + self.body['Description'];
    if (self.repository.type !== 'admin') {
      sendEmail('info@photomenu.nl','photomenushares@gmail.com','Edit Restaurant', strHTMLMailBody, strMailBody, null);
    }
    // email edit restaurant

    if (id === 'new') {
      params.id = uuidV4();
    }
    params.restaurant.images = [];
    if (self.files.length > 0) {
      let allUploads = [];
      self.files.forEach(file => {

        const options = {
          destination: `${params.id}/${uuidV4()}-${file.filename}`
        }
        let upload = {};
//        console.log('408 file.name:' + file.name);
        if (file.name === 'thumbnail') {
          if (file.length > 1000000 || file.width > 1500 || file.height > 1500) {
            upload = new Promise(function (resolve, reject) {

              const resizedPath = path.normalize(`${__dirname}/../tmp/${file.filename}`);

              gm(file.path).resize(1500, 1500).write(resizedPath, err => {
                  if (err) {
                    reject(err);
                  }

                  gm(file.path).thumb(1500, 0, resizedPath, 0, err => {
                    F.storage.upload(resizedPath, options, function (err, uploaded, apiResponse) {
                      if (err) {
                        return reject(err);
                      }
                      uploaded.makePublic(err => reject(err));
                      params.restaurant.thumbnail = uploaded.metadata.mediaLink;
                      resolve(uploaded.metadata.mediaLink);
                    })
                  })
                });
            });
          } else {
            upload = new Promise(function (resolve, reject) {
              F.storage.upload(file.path, options, function (err, file, apiResponse) {
                if (err) {
                  return reject(err);
                }
                file.makePublic(err => reject(err));

                params.restaurant.thumbnail = file.metadata.mediaLink;
                resolve(file.metadata.mediaLink);
              })
            });
          }
        } else {
          //multiple image upload
          console.log('file.length:' + file.length);
          if (file.length > 1000000 || file.width > 1500 || file.height > 1500) {
            upload = new Promise(function (resolve, reject) {
              const resizedPath = path.normalize(`${__dirname}/../tmp/${file.filename}`);
              console.log('resizedPath:' + resizedPath);
              gm(file.path).resize(1500, 1500).write(resizedPath, err => {
                if (err) {
                  reject(err);
                }

                gm(file.path).thumb(1500, 0, resizedPath, 0, err => {
                  F.storage.upload(resizedPath, options, function (err, uploaded, apiResponse) {
                    if (err) {
                      return reject(err);
                    }
                    uploaded.makePublic(err => reject(err));
                    params.restaurant.images.push(uploaded.metadata.mediaLink);
                    resolve(uploaded.metadata.mediaLink);
                  })
                })
              });
            });
          } else {
            upload = new Promise(function (resolve, reject) {
              console.log('file.path:' + file.path);
              F.storage.upload(file.path, options, function (err, file, apiResponse) {
                if (err) {
                  return reject(err);
                }
                file.makePublic(err => reject(err));
                params.restaurant.images.push(file.metadata.mediaLink);
                resolve(file.metadata.mediaLink);
              })
            });
          }
        }
        allUploads.push(upload);
      });
      Promise.all(allUploads).then(() => {
        if (id === 'new') {
          F.model('restaurant').create(params).then(function () {
            self.res.redirect('/restaurants');
          }).catch(err => {
            console.log(err);
            params.error = true;
            params.errorMessage = err;
            params.id = id;
            self.layout('/layouts/protected');
            self.view('/restaurants/edit', params);
          });
        } else {
          F.firebase('/Restaurant/' + params.id).once('value').then(function (old) {
            const oldData = old.val() || {};
            oldData.images = oldData.images || [];
            // Don't replace existing images.
            params.restaurant.images = params.restaurant.images.concat(oldData.images);
            params.restaurant.thumbnail = params.restaurant.thumbnail === '' ? oldData.thumbnail : params.restaurant.thumbnail || oldData.thumbnail;
            // Credits check.
            if (self.repository.type === 'admin') {
              self.body['Credits'] = parseInt(self.body['Credits']);
            } else {
              self.body['Credits'] = oldData.Credits;
            }
            F.model('restaurant').edit(params).then(function () {
              self.res.redirect('/restaurants');
            }).catch(err => {
              console.log(err);
              params.error = true;
              params.errorMessage = err;
              self.layout('/layouts/protected');
              self.view('/restaurants/edit', params);
            });
          });
        }

      }).catch(err => {
        console.log('Error uploading photos:', err);
        params.error = true;
        params.errorMessage = err;
        self.layout('/layouts/protected');
        self.view('/restaurants/edit', params);
      })
    } else {
      F.firebase('/Restaurant/' + params.id).once('value').then(function (old) {
        const oldData = old.val();
        params.restaurant.images = oldData.images;
        params.restaurant.thumbnail = oldData.thumbnail;
        // Credits check.
        if (self.repository.type === 'admin') {
          self.body['Credits'] = parseInt(self.body['Credits']);
        } else {
          self.body['Credits'] = oldData.Credits;
        }
        F.model('restaurant').edit(params).then(function () {
          self.res.redirect('/restaurants');
        }).catch(err => {
          console.log(err);
          params.error = true;
          params.errorMessage = err;
          self.layout('/layouts/protected');
          self.view('/restaurants/edit', params);
        });
      });
    }
  }


};

function restraurantsDelete(id) {
  var self = this;
  F.model('restaurant').delete(id).then(() => {
    F.storage.deleteFiles({
      prefix: `${id}/`
    }, function (err) {
      if (!err) {
        self.res.redirect('/restaurants');
      } else {
        console.log("Error when deleting restaurant:", err);
        self.res.redirect('/restaurants');
      }
    });
  }).catch((err) => {
    console.log("Error when deleting restaurant::", err);
    self.res.redirect('/restaurants');
  })
};