<commit_before>const async = require("async");
const models = require("../../models");
const log = require('../utils/logger');
const queue = require('./queue');
const i18n = require('../utils/i18n');
const toJson = require('../utils/to_json');
const _ = require('lodash');
const getAnonymousUser = require('../utils/get_anonymous_system_user');
var downloadFile = require('download-file');
const fs = require('fs');

let speech, Storage;
let GOOGLE_APPLICATION_CREDENTIALS;
if (process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON && process.env.GOOGLE_TRANSCODING_FLAC_BUCKET) {
  const config = {
    projectId: 'neon-particle-735',
    credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
  };
  GOOGLE_APPLICATION_CREDENTIALS=JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON);
  speech = require('@google-cloud/speech').v1p1beta1;
  Storage = require('@google-cloud/storage').Storage;
}

let airbrake = null;
if(process.env.AIRBRAKE_PROJECT_ID) {
  airbrake = require('../utils/airbrake');
}

let VoiceToTextWorker = function () {};

const supportedGoogleLanguges = [
  ['af-ZA',true,false],
  ['am-ET',true,false],
  ['hy-AM',true,false],
  ['az-AZ',true,false],
  ['id-ID',true,false],
  ['ms-MY',true,false],
  ['bn-BD',false,true],
  ['bn-IN',true,false],
  ['ca-ES',true,false],
  ['cs-CZ',true,false],
  ['da-DK',true,false],
  ['de-DE',true,false],
  ['en-AU',false,false],
  ['en-CA',false,false],
  ['en-GH',false,false],
  ['en-GB',false,true],
  ['en-IN',false,false],
  ['en-IE',false,false],
  ['en-KE',false,false],
  ['en-NZ',false,false],
  ['en-NG',false,false],
  ['en-PH',false,false],
  ['en-ZA',false,false],
  ['en-TZ',false,false],
  ['en-US',true,false],
  ['es-AR',false,false],
  ['es-BO',false,false],
  ['es-CL',false,false],
  ['es-CO',false,false],
  ['es-CR',false,false],
  ['es-EC',false,false],
  ['es-SV',false,false],
  ['es-ES',true,false],
  ['es-US',true,false],
  ['es-GT',false,false],
  ['es-HN',false,false],
  ['es-MX',false,true],
  ['es-NI',false,false],
  ['es-PA',false,false],
  ['es-PY',false,false],
  ['es-PE',false,false],
  ['es-PR',false,false],
  ['es-DO',false,false],
  ['es-UY',false,false],
  ['es-VE',false,false],
  ['eu-ES',true,false],
  ['fil-PH',true,false],
  ['fr-CA',false,true],
  ['fr-FR',true,false],
  ['gl-ES',true,false],
  ['ka-GE',true,false],
  ['gu-IN',true,false],
  ['hr-HR',true,false],
  ['zu-ZA',true,false],
  ['is-IS',true,false],
  ['it-IT',true,false],
  ['jv-ID',true,false],
  ['kn-IN',true,false],
  ['km-KH',true,false],
  ['lo-LA',true,false],
  ['lv-LV',true,false],
  ['lt-LT',true,false],
  ['hu-HU',true,false],
  ['ml-IN',true,false],
  ['mr-IN',true,false],
  ['nl-NL',true,false],
  ['ne-NP',true,false],
  ['nb-NO',true,false],
  ['pl-PL',true,false],
  ['pt-BR',false,true],
  ['pt-PT',true,false],
  ['ro-RO',true,false],
  ['si-LK',true,false],
  ['sk-SK',true,false],
  ['sl-SI',true,false],
  ['su-ID',true,false],
  ['sw-TZ',true,false],
  ['sw-KE',true,false],
  ['fi-FI',true,false],
  ['sv-SE',true,false],
  ['ta-IN',true,false],
  ['ta-SG',false,false],
  ['ta-LK',false,false],
  ['ta-MY',false,true],
  ['te-IN',true,false],
  ['vi-VN',true,false],
  ['tr-TR',true,false],
  ['ur-PK',true,false],
  ['ur-IN',true,false],
  ['el-GR',true,false],
  ['bg-BG',true,false],
  ['ru-RU',true,false],
  ['sr-RS',true,false],
  ['uk-UA',true,false],
  ['he-IL',true,false],
  ['ar-IL',false,true],
  ['ar-JO',false,false],
  ['ar-AE',false,false],
  ['ar-BH',false,false],
  ['ar-DZ',false,false],
  ['ar-SA',false,false],
  ['ar-IQ',false,false],
  ['ar-KW',false,false],
  ['ar-MA',false,false],
  ['ar-TN',false,false],
  ['ar-OM',false,false],
  ['ar-PS',false,false],
  ['ar-QA',false,false],
  ['ar-LB',false,false],
  ['ar-EG',true,false],
  ['fa-IR',true,false],
  ['hi-IN',true,false],
  ['th-TH',true,false],
  ['ko-KR',true,false],
  ['cmn-Hant-TW',false,true],
  ['yue-Hant-HK',true,false],
  ['ja-JP',true,false],
  ['cmn-Hans-HK',false,false],
  ['cmn-Hans-CN',true,false]
];

const transformYrpriCode = (code) => {
  return code.replace('_','-').replace('zh_TW','cmn-Hant-TW').replace('no','nb-NO');
};

const exactLanguageMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    if (language[0]===code)
      match = language[0]
  });
  return match;
};

const firstTwoLanguagePrimaryMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    const enCode = language[0].substring(0,3);
    const chineseCode = language[0].substring(0,4);
    if (enCode===code+'-' && language[1]===true)
      match = language[0];
    if (chineseCode===code+'-' && language[1]===true)
      match = language[0];
  });
  return match;
};

const firstTwoLanguageSecondaryMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    if (language[0].substring(0,3)===code+'-' && language[2]===true)
      match = language[0];
    if (language[0].substring(0,4)===code+'-' && language[2]===true)
      match = language[0];
  });
  return match;
};

const getLanguageArray = (workPackage) => {

  let alternativeLanguageCodes = [];
  let languageCode = null;
  const appLanguage = workPackage.appLanguage;
  const browserLanguage = workPackage.browserLanguage;

  if (appLanguage && appLanguage) {
    let exactAppMatch = exactLanguageMatch(appLanguage);
    let primaryAppMatch = firstTwoLanguagePrimaryMatch(appLanguage);
    let secondaryAppMatch = firstTwoLanguageSecondaryMatch(appLanguage);
    let exactBrowserMatch = exactLanguageMatch(browserLanguage);
    let primaryBrowserMatch = firstTwoLanguagePrimaryMatch(browserLanguage);
    let secondaryBrowserMatch = firstTwoLanguageSecondaryMatch(browserLanguage);

    if (exactAppMatch)
      languageCode = exactAppMatch;
    else if (primaryAppMatch)
      languageCode = primaryAppMatch;
    else if (secondaryAppMatch)
      languageCode = secondaryAppMatch;
    else if (exactBrowserMatch)
      languageCode = exactBrowserMatch;
    else if (primaryBrowserMatch)
      languageCode = primaryBrowserMatch;

    if (!languageCode) {
      return null
    } else {
      if (exactAppMatch && exactAppMatch!==languageCode)
        alternativeLanguageCodes.push(exactAppMatch);
      if (primaryAppMatch && primaryAppMatch!==languageCode)
        alternativeLanguageCodes.push(primaryAppMatch);
      if (secondaryAppMatch && secondaryAppMatch!==languageCode)
        alternativeLanguageCodes.push(secondaryAppMatch);
      if (exactBrowserMatch && exactBrowserMatch!==languageCode)
        alternativeLanguageCodes.push(exactBrowserMatch);
      if (primaryBrowserMatch && primaryBrowserMatch!==languageCode)
        alternativeLanguageCodes.push(primaryBrowserMatch);
      if (secondaryBrowserMatch)
        alternativeLanguageCodes.push(primaryBrowserMatch)
    }

    alternativeLanguageCodes = _.uniq(alternativeLanguageCodes);

    if (alternativeLanguageCodes.length<3)
      alternativeLanguageCodes.push("en-US");
   // if (alternativeLanguageCodes.length<3)
   //   alternativeLanguageCodes.push("is-IS");

    if (alternativeLanguageCodes.length<3)
      alternativeLanguageCodes = alternativeLanguageCodes.slice(0,3);

    const languageSelection = { languageCode, alternativeLanguageCodes };
    log.info("Selected languages for transcript", languageSelection, workPackage);

    return languageSelection;
  } else {
    return null;
  }

};

const createTranscriptForFlac = (flackUrl, workPackage, callback) => {

  const languageSelection = getLanguageArray(workPackage);

  if (languageSelection && speech) {
    const client = new speech.SpeechClient({
      credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
    });

    const encoding = 'FLAC';
    const sampleRateHertz = 44100;

    const config = {
      encoding: encoding,
      sampleRateHertz: sampleRateHertz,
      languageCode: languageSelection.languageCode,
      alternativeLanguageCodes: languageSelection.alternativeLanguageCodes,
      enableWordTimeOffsets: true,
      enableAutomaticPunctuation: true,
      enableWordConfidence: true
    };

    const audio = {
      uri: flackUrl,
    };

    const request = {
      config: config,
      audio: audio,
    };

    log.info("Starting speech to text", { request });
    client
      .longRunningRecognize(request)
      .then(data => {
        const operation = data[0];
        // Get a Promise representation of the final result of the job
        return operation.promise();
      })
      .then(data => {
        log.info("Got data from google cloud", { data });
        callback(null, data[0]);
      })
      .catch(error => {
        callback(error);
      });
  } else {
    log.warn("Can't find any languages to translate or speech not here", { workPackage, speechNull: speech==null});
    callback("Can't find languages");
  }
};

const uploadFlacToGoogleCloud = (flacUrl, callback) => {
  const splitUrl = flacUrl.split('/');
  const fileName =  splitUrl[splitUrl.length-1];
  const fileNameWithPath = '/tmp/'+fileName;
  const fileUri = 'gs://'+process.env.GOOGLE_TRANSCODING_FLAC_BUCKET+'/'+fileName;

  downloadFile(flacUrl, { filename: fileName, directory: '/tmp/'}, error => {
    if (error) {
      fs.unlink(fileNameWithPath, unlinkError => {
        callback('Could not download file');
      })
    } else {
      const storage = new Storage({
        credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
      });
      const bucket = storage.bucket(process.env.GOOGLE_TRANSCODING_FLAC_BUCKET);
      if (bucket) {
        bucket.upload(fileNameWithPath, (error, file, apiReponse) => {
          if (error) {
            log.error("Couldnt upload to s3 bucket", {error, apiResponse});
            fs.unlink(fileNameWithPath, unlinkError => {
              callback(error);
            });
          } else {
            fs.unlink(fileNameWithPath, error => {
              if (error) {
                callback(error)
              } else {
                log.info("uploadFlacToGoogleCloud done", { flacUrl });
                callback(null, fileUri);
              }
            });
          }
        })
      } else {
        fs.unlink(fileNameWithPath, unlinkError => {
          callback('Could not find GCloud bucket');
        });
      }
    }
  })
};

const createTranscriptForVideo = (workPackage, callback) => {
  models.Video.find({
    where: workPackage.videoId
  }).then((video) => {
    if (video) {
      const videoUrl = video.formats[0];
      const flacUrl = videoUrl.slice(0, videoUrl.length-4)+'.flac';
      uploadFlacToGoogleCloud(flacUrl, (error, gsUri) => {
        if (error) {
          callback(error);
        } else {
          createTranscriptForFlac(gsUri, workPackage, (error, response) => {
            if (!video.meta.transcripts)
              video.set('meta.transcript', {});
            video.set('meta.transcript.googleSpeechResponse', response);
            if (error) {
              video.set('meta.transcript.error', error);
            } else {
              if (response.results && response.results && response.results.length>0 &&
                response.results[0].alternatives && response.results[0].alternatives.length>0) {
                const transcription = response.results
                  .map(result => result.alternatives[0].transcript)
                  .join('\n');
                video.set('meta.transcript.text', transcription);
              } else {
                video.set('meta.transcript.error', 'Found no text');
              }
            }
            video.save().then(() => {
              log.info("Video with transcript saved", { videoId: workPackage.videoId, error });
              callback()
            }).catch((error) => {
              callback(error);
            });
          });
        }
      });
    } else {
      callback("Couldn't find video for createTranscriptForVideo", { workPackage });
    }
  }).catch((error) => {
    callback(error);
  })
};

const createTranscriptForAudio = (workPackage, callback) => {
  models.Audio.find({
    where: workPackage.audioId
  }).then((audio) => {
    if (audio) {
      const audioUrl = audio.formats[0];
      const flacUrl = audioUrl.slice(0, audioUrl.length-4)+'.flac';
      uploadFlacToGoogleCloud(flacUrl, (error, gsUri) => {
        if (error) {
          callback(error);
        } else {
          createTranscriptForFlac(gsUri, workPackage, (error, response) => {
            if (!audio.meta.transcripts)
              audio.set('meta.transcript', {});
            audio.set('meta.transcript.googleSpeechResponse', response);
            if (error) {
              audio.set('meta.transcript.error', error);
            } else {
              if (response.results && response.results && response.results.length>0 &&
                response.results[0].alternatives && response.results[0].alternatives.length>0) {
                const transcription = response.results
                  .map(result => result.alternatives[0].transcript)
                  .join('\n');
                audio.set('meta.transcript.text', transcription);
              } else {
                audio.set('meta.transcript.error', 'Found no text');
              }
            }
            audio.save().then(() => {
              log.info("Audio with transcript saved", { audioId: workPackage.audioId, error });
              callback()
            }).catch((error) => {
              callback(error);
            });
          });
        }
      });
    } else {
      callback("Couldn't find audio for createTranscriptForAudio", { workPackage });
    }
  }).catch((error) => {
    callback(error);
  })
};

VoiceToTextWorker.prototype.process = (workPackage, callback) => {
  switch (workPackage.type) {
    case 'create-video-transcript':
      createTranscriptForVideo(workPackage, callback);
      break;
    case 'create-audio-transcript':
      createTranscriptForAudio(workPackage, callback);
      break;
    default:
      callback("Unknown type for workPackage: "+workPackage.type);
  }
};

module.exports = new VoiceToTextWorker();
<commit_msg>Disable alternativeLanguageCodes for now as it is not working well enough for long form audio<commit_after>const async = require("async");
const models = require("../../models");
const log = require('../utils/logger');
const queue = require('./queue');
const i18n = require('../utils/i18n');
const toJson = require('../utils/to_json');
const _ = require('lodash');
const getAnonymousUser = require('../utils/get_anonymous_system_user');
var downloadFile = require('download-file');
const fs = require('fs');

let speech, Storage;
let GOOGLE_APPLICATION_CREDENTIALS;
if (process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON && process.env.GOOGLE_TRANSCODING_FLAC_BUCKET) {
  const config = {
    projectId: 'neon-particle-735',
    credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
  };
  GOOGLE_APPLICATION_CREDENTIALS=JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON);
  speech = require('@google-cloud/speech').v1p1beta1;
  Storage = require('@google-cloud/storage').Storage;
}

let airbrake = null;
if(process.env.AIRBRAKE_PROJECT_ID) {
  airbrake = require('../utils/airbrake');
}

let VoiceToTextWorker = function () {};

const supportedGoogleLanguges = [
  ['af-ZA',true,false],
  ['am-ET',true,false],
  ['hy-AM',true,false],
  ['az-AZ',true,false],
  ['id-ID',true,false],
  ['ms-MY',true,false],
  ['bn-BD',false,true],
  ['bn-IN',true,false],
  ['ca-ES',true,false],
  ['cs-CZ',true,false],
  ['da-DK',true,false],
  ['de-DE',true,false],
  ['en-AU',false,false],
  ['en-CA',false,false],
  ['en-GH',false,false],
  ['en-GB',false,true],
  ['en-IN',false,false],
  ['en-IE',false,false],
  ['en-KE',false,false],
  ['en-NZ',false,false],
  ['en-NG',false,false],
  ['en-PH',false,false],
  ['en-ZA',false,false],
  ['en-TZ',false,false],
  ['en-US',true,false],
  ['es-AR',false,false],
  ['es-BO',false,false],
  ['es-CL',false,false],
  ['es-CO',false,false],
  ['es-CR',false,false],
  ['es-EC',false,false],
  ['es-SV',false,false],
  ['es-ES',true,false],
  ['es-US',true,false],
  ['es-GT',false,false],
  ['es-HN',false,false],
  ['es-MX',false,true],
  ['es-NI',false,false],
  ['es-PA',false,false],
  ['es-PY',false,false],
  ['es-PE',false,false],
  ['es-PR',false,false],
  ['es-DO',false,false],
  ['es-UY',false,false],
  ['es-VE',false,false],
  ['eu-ES',true,false],
  ['fil-PH',true,false],
  ['fr-CA',false,true],
  ['fr-FR',true,false],
  ['gl-ES',true,false],
  ['ka-GE',true,false],
  ['gu-IN',true,false],
  ['hr-HR',true,false],
  ['zu-ZA',true,false],
  ['is-IS',true,false],
  ['it-IT',true,false],
  ['jv-ID',true,false],
  ['kn-IN',true,false],
  ['km-KH',true,false],
  ['lo-LA',true,false],
  ['lv-LV',true,false],
  ['lt-LT',true,false],
  ['hu-HU',true,false],
  ['ml-IN',true,false],
  ['mr-IN',true,false],
  ['nl-NL',true,false],
  ['ne-NP',true,false],
  ['nb-NO',true,false],
  ['pl-PL',true,false],
  ['pt-BR',false,true],
  ['pt-PT',true,false],
  ['ro-RO',true,false],
  ['si-LK',true,false],
  ['sk-SK',true,false],
  ['sl-SI',true,false],
  ['su-ID',true,false],
  ['sw-TZ',true,false],
  ['sw-KE',true,false],
  ['fi-FI',true,false],
  ['sv-SE',true,false],
  ['ta-IN',true,false],
  ['ta-SG',false,false],
  ['ta-LK',false,false],
  ['ta-MY',false,true],
  ['te-IN',true,false],
  ['vi-VN',true,false],
  ['tr-TR',true,false],
  ['ur-PK',true,false],
  ['ur-IN',true,false],
  ['el-GR',true,false],
  ['bg-BG',true,false],
  ['ru-RU',true,false],
  ['sr-RS',true,false],
  ['uk-UA',true,false],
  ['he-IL',true,false],
  ['ar-IL',false,true],
  ['ar-JO',false,false],
  ['ar-AE',false,false],
  ['ar-BH',false,false],
  ['ar-DZ',false,false],
  ['ar-SA',false,false],
  ['ar-IQ',false,false],
  ['ar-KW',false,false],
  ['ar-MA',false,false],
  ['ar-TN',false,false],
  ['ar-OM',false,false],
  ['ar-PS',false,false],
  ['ar-QA',false,false],
  ['ar-LB',false,false],
  ['ar-EG',true,false],
  ['fa-IR',true,false],
  ['hi-IN',true,false],
  ['th-TH',true,false],
  ['ko-KR',true,false],
  ['cmn-Hant-TW',false,true],
  ['yue-Hant-HK',true,false],
  ['ja-JP',true,false],
  ['cmn-Hans-HK',false,false],
  ['cmn-Hans-CN',true,false]
];

const transformYrpriCode = (code) => {
  return code.replace('_','-').replace('zh_TW','cmn-Hant-TW').replace('no','nb-NO');
};

const exactLanguageMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    if (language[0]===code)
      match = language[0]
  });
  return match;
};

const firstTwoLanguagePrimaryMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    const enCode = language[0].substring(0,3);
    const chineseCode = language[0].substring(0,4);
    if (enCode===code+'-' && language[1]===true)
      match = language[0];
    if (chineseCode===code+'-' && language[1]===true)
      match = language[0];
  });
  return match;
};

const firstTwoLanguageSecondaryMatch = (code) => {
  code = transformYrpriCode(code);
  let match = null;
  _.forEach(supportedGoogleLanguges, (language) => {
    if (language[0].substring(0,3)===code+'-' && language[2]===true)
      match = language[0];
    if (language[0].substring(0,4)===code+'-' && language[2]===true)
      match = language[0];
  });
  return match;
};

const getLanguageArray = (workPackage) => {

  let alternativeLanguageCodes = [];
  let languageCode = null;
  const appLanguage = workPackage.appLanguage;
  const browserLanguage = workPackage.browserLanguage;

  if (appLanguage && appLanguage) {
    let exactAppMatch = exactLanguageMatch(appLanguage);
    let primaryAppMatch = firstTwoLanguagePrimaryMatch(appLanguage);
    let secondaryAppMatch = firstTwoLanguageSecondaryMatch(appLanguage);
    let exactBrowserMatch = exactLanguageMatch(browserLanguage);
    let primaryBrowserMatch = firstTwoLanguagePrimaryMatch(browserLanguage);
    let secondaryBrowserMatch = firstTwoLanguageSecondaryMatch(browserLanguage);

    if (exactAppMatch)
      languageCode = exactAppMatch;
    else if (primaryAppMatch)
      languageCode = primaryAppMatch;
    else if (secondaryAppMatch)
      languageCode = secondaryAppMatch;
    else if (exactBrowserMatch)
      languageCode = exactBrowserMatch;
    else if (primaryBrowserMatch)
      languageCode = primaryBrowserMatch;

    if (!languageCode) {
      return null
    } else {
      if (exactAppMatch && exactAppMatch!==languageCode)
        alternativeLanguageCodes.push(exactAppMatch);
      if (primaryAppMatch && primaryAppMatch!==languageCode)
        alternativeLanguageCodes.push(primaryAppMatch);
      if (secondaryAppMatch && secondaryAppMatch!==languageCode)
        alternativeLanguageCodes.push(secondaryAppMatch);
      if (exactBrowserMatch && exactBrowserMatch!==languageCode)
        alternativeLanguageCodes.push(exactBrowserMatch);
      if (primaryBrowserMatch && primaryBrowserMatch!==languageCode)
        alternativeLanguageCodes.push(primaryBrowserMatch);
      if (secondaryBrowserMatch)
        alternativeLanguageCodes.push(primaryBrowserMatch)
    }

    alternativeLanguageCodes = _.uniq(alternativeLanguageCodes);

    if (alternativeLanguageCodes.length<3)
      alternativeLanguageCodes.push("en-US");
   // if (alternativeLanguageCodes.length<3)
   //   alternativeLanguageCodes.push("is-IS");

    if (alternativeLanguageCodes.length>3)
      alternativeLanguageCodes = alternativeLanguageCodes.slice(0,3);

    const languageSelection = { languageCode, alternativeLanguageCodes };
    log.info("Selected languages for transcript", languageSelection, workPackage);

    return languageSelection;
  } else {
    return null;
  }

};

const createTranscriptForFlac = (flackUrl, workPackage, callback) => {

  const languageSelection = getLanguageArray(workPackage);

  if (languageSelection && speech) {
    const client = new speech.SpeechClient({
      credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
    });

    const encoding = 'FLAC';
    const sampleRateHertz = 44100;

    const config = {
      encoding: encoding,
      sampleRateHertz: sampleRateHertz,
      languageCode: languageSelection.languageCode,
      // Disabled for now as it does not work well enough for long form content
      //alternativeLanguageCodes: languageSelection.alternativeLanguageCodes,
      enableWordTimeOffsets: true,
      enableAutomaticPunctuation: true,
      enableWordConfidence: true
    };

    const audio = {
      uri: flackUrl,
    };

    const request = {
      config: config,
      audio: audio,
    };

    log.info("Starting speech to text", { request });
    client
      .longRunningRecognize(request)
      .then(data => {
        const operation = data[0];
        // Get a Promise representation of the final result of the job
        return operation.promise();
      })
      .then(data => {
        log.info("Got data from google cloud", { data });
        callback(null, data[0]);
      })
      .catch(error => {
        callback(error);
      });
  } else {
    log.warn("Can't find any languages to translate or speech not here", { workPackage, speechNull: speech==null});
    callback("Can't find languages");
  }
};

const uploadFlacToGoogleCloud = (flacUrl, callback) => {
  const splitUrl = flacUrl.split('/');
  const fileName =  splitUrl[splitUrl.length-1];
  const fileNameWithPath = '/tmp/'+fileName;
  const fileUri = 'gs://'+process.env.GOOGLE_TRANSCODING_FLAC_BUCKET+'/'+fileName;

  downloadFile(flacUrl, { filename: fileName, directory: '/tmp/'}, error => {
    if (error) {
      fs.unlink(fileNameWithPath, unlinkError => {
        callback('Could not download file');
      })
    } else {
      const storage = new Storage({
        credentials: JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON)
      });
      const bucket = storage.bucket(process.env.GOOGLE_TRANSCODING_FLAC_BUCKET);
      if (bucket) {
        bucket.upload(fileNameWithPath, (error, file, apiReponse) => {
          if (error) {
            log.error("Couldnt upload to s3 bucket", {error, apiResponse});
            fs.unlink(fileNameWithPath, unlinkError => {
              callback(error);
            });
          } else {
            fs.unlink(fileNameWithPath, error => {
              if (error) {
                callback(error)
              } else {
                log.info("uploadFlacToGoogleCloud done", { flacUrl });
                callback(null, fileUri);
              }
            });
          }
        })
      } else {
        fs.unlink(fileNameWithPath, unlinkError => {
          callback('Could not find GCloud bucket');
        });
      }
    }
  })
};

const createTranscriptForVideo = (workPackage, callback) => {
  models.Video.find({
    where: workPackage.videoId
  }).then((video) => {
    if (video) {
      const videoUrl = video.formats[0];
      const flacUrl = videoUrl.slice(0, videoUrl.length-4)+'.flac';
      uploadFlacToGoogleCloud(flacUrl, (error, gsUri) => {
        if (error) {
          callback(error);
        } else {
          createTranscriptForFlac(gsUri, workPackage, (error, response) => {
            if (!video.meta.transcripts)
              video.set('meta.transcript', {});
            video.set('meta.transcript.googleSpeechResponse', response);
            if (error) {
              video.set('meta.transcript.error', error);
            } else {
              if (response.results && response.results && response.results.length>0 &&
                response.results[0].alternatives && response.results[0].alternatives.length>0) {
                const transcription = response.results
                  .map(result => result.alternatives[0].transcript)
                  .join('\n');
                video.set('meta.transcript.text', transcription);
              } else {
                video.set('meta.transcript.error', 'Found no text');
              }
            }
            video.save().then(() => {
              log.info("Video with transcript saved", { videoId: workPackage.videoId, error });
              callback()
            }).catch((error) => {
              callback(error);
            });
          });
        }
      });
    } else {
      callback("Couldn't find video for createTranscriptForVideo", { workPackage });
    }
  }).catch((error) => {
    callback(error);
  })
};

const createTranscriptForAudio = (workPackage, callback) => {
  models.Audio.find({
    where: workPackage.audioId
  }).then((audio) => {
    if (audio) {
      const audioUrl = audio.formats[0];
      const flacUrl = audioUrl.slice(0, audioUrl.length-4)+'.flac';
      uploadFlacToGoogleCloud(flacUrl, (error, gsUri) => {
        if (error) {
          callback(error);
        } else {
          createTranscriptForFlac(gsUri, workPackage, (error, response) => {
            if (!audio.meta.transcripts)
              audio.set('meta.transcript', {});
            audio.set('meta.transcript.googleSpeechResponse', response);
            if (error) {
              audio.set('meta.transcript.error', error);
            } else {
              if (response.results && response.results && response.results.length>0 &&
                response.results[0].alternatives && response.results[0].alternatives.length>0) {
                const transcription = response.results
                  .map(result => result.alternatives[0].transcript)
                  .join('\n');
                audio.set('meta.transcript.text', transcription);
              } else {
                audio.set('meta.transcript.error', 'Found no text');
              }
            }
            audio.save().then(() => {
              log.info("Audio with transcript saved", { audioId: workPackage.audioId, error });
              callback()
            }).catch((error) => {
              callback(error);
            });
          });
        }
      });
    } else {
      callback("Couldn't find audio for createTranscriptForAudio", { workPackage });
    }
  }).catch((error) => {
    callback(error);
  })
};

VoiceToTextWorker.prototype.process = (workPackage, callback) => {
  switch (workPackage.type) {
    case 'create-video-transcript':
      createTranscriptForVideo(workPackage, callback);
      break;
    case 'create-audio-transcript':
      createTranscriptForAudio(workPackage, callback);
      break;
    default:
      callback("Unknown type for workPackage: "+workPackage.type);
  }
};

module.exports = new VoiceToTextWorker();
<|endoftext|>


<commit_before>/*
 (c) 2014, Vladimir Agafonkin
 simpleheat, a tiny JavaScript library for drawing heatmaps with Canvas
 https://github.com/mourner/simpleheat
*/

'use strict';

function simpleheat(canvas) {
    // jshint newcap: false, validthis: true
    if (!(this instanceof simpleheat)) { return new simpleheat(canvas); }

    this._canvas = canvas = typeof canvas === 'string' ? document.getElementById(canvas) : canvas;

    this._ctx = canvas.getContext('2d');
    this._width = canvas.width;
    this._height = canvas.height;

    this._max = 1;
    this._data = [];
}

simpleheat.prototype = {

    defaultRadius: 25,

    defaultGradient: {
        0.4: 'blue',
        0.6: 'cyan',
        0.7: 'lime',
        0.8: 'yellow',
        1.0: 'red'
    },

    data: function (data) {
        this._data = data;
        return this;
    },

    max: function (max) {
        this._max = max;
        return this;
    },

    add: function (point) {
        this._data.push(point);
        return this;
    },

    clear: function () {
        this._data = [];
        return this;
    },

    radius: function (r, blur) {
        blur = blur || 15;

        // create a grayscale blurred circle image that we'll use for drawing points
        var circle = this._circle = document.createElement('canvas'),
            ctx = circle.getContext('2d'),
            r2 = this._r = r + blur;

        circle.width = circle.height = r2 * 2;

        ctx.shadowOffsetX = ctx.shadowOffsetY = 200;
        ctx.shadowBlur = blur;
        ctx.shadowColor = 'black';

        ctx.beginPath();
        ctx.arc(r2 - 200, r2 - 200, r, 0, Math.PI * 2, true);
        ctx.closePath();
        ctx.fill();

        return this;
    },

    gradient: function (grad) {
        // create a 256x1 gradient that we'll use to turn a grayscale heatmap into a colored one
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            gradient = ctx.createLinearGradient(0, 0, 0, 256);

        canvas.width = 1;
        canvas.height = 256;

        for (var i in grad) {
            gradient.addColorStop(i, grad[i]);
        }

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, 1, 256);

        this._grad = ctx.getImageData(0, 0, 1, 256).data;

        return this;
    },

    draw: function (minOpacity, pos) {
        if (!this._circle) {
            this.radius(this.defaultRadius);
        }
        if (!this._grad) {
            this.gradient(this.defaultGradient);
        }

        var ctx = this._ctx;

        //ctx.clearRect(0, 0, this._width, this._height);

        // draw a grayscale heatmap by putting a blurred circle at each data point
        // for (var i = 0, len = this._data.length, p; i < len; i++) {
        //     p = this._data[i];
        //     ctx.globalAlpha = Math.max(p[2] / this._max, minOpacity === undefined ? 0.05 : minOpacity);
        //     ctx.drawImage(this._circle, p[0] - this._r, p[1] - this._r);
        // }

        // colorize the heatmap, using opacity value of each pixel to get the right color from our gradient
        var colored = ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);
        this._colorize(colored.data, this._grad);
        ctx.putImageData(colored, 0, 0);

        return this;
    },

    _colorize: function (pixels, gradient) {
        for (var i = 3, len = pixels.length, j; i < len; i += 4) {
            j = pixels[i] * 4; // get gradient color from opacity value

            if (j) {
                pixels[i - 3] = gradient[j];
                pixels[i - 2] = gradient[j + 1];
                pixels[i - 1] = gradient[j + 2];
            }
        }
    }
};

module.exports = simpleheat;
<commit_msg>removes unnecessary code in simpleheat<commit_after>/*
 (c) 2014, Vladimir Agafonkin
 simpleheat, a tiny JavaScript library for drawing heatmaps with Canvas
 https://github.com/mourner/simpleheat
*/

'use strict';

function simpleheat(canvas) {
    // jshint newcap: false, validthis: true
    if (!(this instanceof simpleheat)) { return new simpleheat(canvas); }

    this._canvas = canvas = typeof canvas === 'string' ? document.getElementById(canvas) : canvas;

    this._ctx = canvas.getContext('2d');
    this._width = canvas.width;
    this._height = canvas.height;

    this._max = 1;
    this._data = [];
}

simpleheat.prototype = {

    defaultRadius: 25,

    defaultGradient: {
        0.4: 'blue',
        0.6: 'cyan',
        0.7: 'lime',
        0.8: 'yellow',
        1.0: 'red'
    },

    data: function (data) {
        this._data = data;
        return this;
    },

    max: function (max) {
        this._max = max;
        return this;
    },

    add: function (point) {
        this._data.push(point);
        return this;
    },

    clear: function () {
        this._data = [];
        return this;
    },

    radius: function (r, blur) {
        blur = blur || 15;

        // create a grayscale blurred circle image that we'll use for drawing points
        var circle = this._circle = document.createElement('canvas'),
            ctx = circle.getContext('2d'),
            r2 = this._r = r + blur;

        circle.width = circle.height = r2 * 2;

        ctx.shadowOffsetX = ctx.shadowOffsetY = 200;
        ctx.shadowBlur = blur;
        ctx.shadowColor = 'black';

        ctx.beginPath();
        ctx.arc(r2 - 200, r2 - 200, r, 0, Math.PI * 2, true);
        ctx.closePath();
        ctx.fill();

        return this;
    },

    gradient: function (grad) {
        // create a 256x1 gradient that we'll use to turn a grayscale heatmap into a colored one
        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d'),
            gradient = ctx.createLinearGradient(0, 0, 0, 256);

        canvas.width = 1;
        canvas.height = 256;

        for (var i in grad) {
            gradient.addColorStop(i, grad[i]);
        }

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, 1, 256);

        this._grad = ctx.getImageData(0, 0, 1, 256).data;

        return this;
    },

    draw: function (minOpacity, pos) {
        if (!this._circle) {
            this.radius(this.defaultRadius);
        }
        if (!this._grad) {
            this.gradient(this.defaultGradient);
        }

        var ctx = this._ctx;
        var colored = ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);
        this._colorize(colored.data, this._grad);
        ctx.putImageData(colored, 0, 0);

        return this;
    },

    _colorize: function (pixels, gradient) {
        for (var i = 3, len = pixels.length, j; i < len; i += 4) {
            j = pixels[i] * 4; // get gradient color from opacity value

            if (j) {
                pixels[i - 3] = gradient[j];
                pixels[i - 2] = gradient[j + 1];
                pixels[i - 1] = gradient[j + 2];
            }
        }
    }
};

module.exports = simpleheat;
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var fs = require('fs');
var path = require('path');
var icecast = require('../');
var assert = require('assert');

describe('Reader', function () {

  describe('4EverFloyd-1-8192.mp3', function () {
    var metaint = 8192;
    var fixture = path.resolve(__dirname, 'fixtures', '4EverFloyd-1-8192.mp3');

    it('should emit one "metadata" event', function (done) {
      var file = fs.createReadStream(fixture);
      var reader = new icecast.Reader(8192);
      var called = false;
      reader.on('metadata', function (metadata) {
        assert(!called);
        assert(Buffer.isBuffer(metadata));
        assert(metadata.length < 4096);
        called = true;
        done();
      });
      file.pipe(reader);
    });

  });

});
<commit_msg>test: add more Reader tests<commit_after>
/**
 * Module dependencies.
 */

var fs = require('fs');
var path = require('path');
var icecast = require('../');
var assert = require('assert');

describe('Reader', function () {

  it('should work with a "metaint" of 1', function (done) {
    var data = 'h\0e\0l\0l\u0001hello world\0\0\0\0\0o\0 \0w\0o\0r\0l\0d';
    var r = new icecast.Reader(1);
    var called = false;
    r.on('metadata', function (metadata) {
      assert(Buffer.isBuffer(metadata));
      assert.equal(16, metadata.length);
      assert.equal('hello world\0\0\0\0\0', metadata.toString('utf8'));
      called = true;
    });
    var output = '';
    r.setEncoding('utf8');
    r.on('data', function (b) {
      output += b;
    });
    r.on('end', function () {
      assert(called);
      assert.equal('hello world', output);
      done();
    });
    r.end(data);
  });

  describe('4EverFloyd-1-8192.mp3', function () {
    var metaint = 8192;
    var fixture = path.resolve(__dirname, 'fixtures', '4EverFloyd-1-8192.mp3');

    it('should emit one "metadata" event', function (done) {
      var file = fs.createReadStream(fixture);
      var reader = new icecast.Reader(8192);
      var called = false;
      reader.on('metadata', function (metadata) {
        assert(!called);
        assert(Buffer.isBuffer(metadata));
        assert(metadata.length < 4096);
        called = true;
        done();
      });
      file.pipe(reader);
    });

  });

  describe('4EverFloyd-2-8192.mp3', function () {
    var metaint = 8192;
    var fixture = path.resolve(__dirname, 'fixtures', '4EverFloyd-2-8192.mp3');

    it('should emit one "metadata" event', function (done) {
      var file = fs.createReadStream(fixture);
      var reader = new icecast.Reader(8192);
      var called = false;
      reader.on('metadata', function (metadata) {
        assert(!called);
        assert(Buffer.isBuffer(metadata));
        assert(metadata.length < 4096);
        called = true;
        done();
      });
      file.pipe(reader);
    });

  });

});
<|endoftext|>


<commit_before>var test = require('tape')
var hyperlog = require('hyperlog')
var memdb = require('memdb')
var path = require('path')
var fdstore = require('fd-chunk-store')
var data = require('./data/refbug.json')
var osmdb = require('../')

var tmpdir = require('os').tmpdir()
var storefile = path.join(tmpdir, 'osm-store-' + Math.random())

test('refbug', function (t) {
  t.plan(data.length + 4)
  var osm = osmdb({
    log: hyperlog(memdb(), { valueEncoding: 'json' }),
    db: memdb(),
    store: fdstore(4096, storefile)
  })
  var nodes = []
  ;(function next (links) {
    if (data.length === 0) return ready()
    var row = data.shift()
    osm.put(row.key, row.value, { links: links }, function (err, node) {
      t.error(err)
      nodes.push(node)
      if (row.value.type === 'node') next([node.key])
      else next([])
    })
  })([])

  function ready () {
    var bbox = [[64,66],[-149,-146]]
    osm.query(bbox, function (err, res) {
      t.error(err)
      t.equal(res.length, 2)
      var node = res.filter(eqtype('node'))[0]
      var way = res.filter(eqtype('way'))[0]
      t.deepEqual(node, {
        type: 'node',
        id: 'n1',
        lat: 64.9,
        lon: -147.9,
        version: nodes[nodes.length-1].key
      })
      t.deepEqual(way, {
        type: 'way',
        id: 'w1',
        refs: [ 'n1' ],
        version: nodes[1].key
      })
    })
  }
})

function eqtype (t) {
  return function (node) { return node.type === t }
}
<commit_msg>fixed refbug test<commit_after>var test = require('tape')
var hyperlog = require('hyperlog')
var memdb = require('memdb')
var path = require('path')
var fdstore = require('fd-chunk-store')
var data = require('./data/refbug.json')
var osmdb = require('../')

var tmpdir = require('os').tmpdir()
var storefile = path.join(tmpdir, 'osm-store-' + Math.random())

test('refbug', function (t) {
  t.plan(data.length + 4)
  var osm = osmdb({
    log: hyperlog(memdb(), { valueEncoding: 'json' }),
    db: memdb(),
    store: fdstore(4096, storefile)
  })
  var nodes = [], docs = {}
  ;(function next () {
    if (data.length === 0) return ready()
    var row = data.shift()
    var prev = docs[row.key]
    var p = prev && prev[prev.length-1]
    var links = p ? [p] : []
    osm.put(row.key, row.value, { links: links }, function (err, node) {
      t.error(err)
      nodes.push(node)
      if (!docs[row.key]) docs[row.key] = []
      docs[row.key].push(node.key)
      next()
    })
  })()

  function ready () {
    var bbox = [[64,66],[-149,-146]]
    osm.query(bbox, function (err, res) {
      t.error(err)
      t.equal(res.length, 2)
      var node = res.filter(eqtype('node'))[0]
      var way = res.filter(eqtype('way'))[0]
      t.deepEqual(node, {
        type: 'node',
        id: 'n1',
        lat: 64.9,
        lon: -147.9,
        version: nodes[nodes.length-1].key
      })
      t.deepEqual(way, {
        type: 'way',
        id: 'w1',
        refs: [ 'n1' ],
        version: nodes[1].key
      })
    })
  }
})

function eqtype (t) {
  return function (node) { return node.type === t }
}
<|endoftext|>


<commit_before>'use strict';

var expect = require('chai').expect;
var express = require('express');
var http = require('http');
var mongoose = require('mongoose');
var request = require('supertest');
var async = require('async');

var setup = require('./setup');

describe('routes', function() {
  var app, conn, User, Comment;

  before(function() {
    conn = setup.models();
  });

  beforeEach(function(done) {
    var ret = setup.data(done);
    app = ret.app;
    User = ret.User;
    Comment = ret.Comment;
  });

  afterEach(function(done) {
    async.parallel([
      function(callback) {
        User.model.remove({}, callback);
      },
      function(callback) {
        Comment.model.remove({}, callback);
      }
    ], done);
  });

  after(function(done) {
    this.timeout(5000);
    conn.db.dropDatabase(function(err) {
      done(err);
    });
  });

  describe('create', function() {
    it('should create a document', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          name: 'Asdflol',
          hobby: 'Baseball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.id).to.equal('Asdflol');
          expect(res.body.name).to.equal('Asdflol');
          done();
        });
    });

    it('should 409 if the document already exists', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          name: 'Bob',
          hobby: 'Soccer'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(409);
          expect(res.body.message).to.match(/User already exists/);
          done();
        });
    });

    it('should create a subdocument', function(done) {
      User.id = 'name';
      request(app).post('/users/Bob/comments')
        .send({
          content: 'Test',
          reaction: 'asdf'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Test');
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            expect(res.body.author).to.equal(bob._id.toString());
            done();
          });
        });
    });

    it('should 409 if the subdocument already exists', function(done) {
      User.id = 'name';
      request(app).post('/users/Bob/comments')
        .send({
          content: 'exists',
          reaction: 'BobL'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(409);
          expect(res.body.message).to.match(/Comment already exists/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          content: 'exists',
          reaction: 'BobL'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.equal('true');
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });
  });

  describe('get', function() {
    it('should get a document by id', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.name).to.equal('Bob');
          done();
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).get('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should get a subdocument by id', function(done) {
      User.id = 'name';
      Comment.id = 'reaction';
      request(app).get('/users/Bob/comments/BobL')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Lol');
          expect(res.body.reaction).to.equal('BobL');
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            expect(res.body.author).to.equal(bob._id.toString());
            done();
          });
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob/comments/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "DNE" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.equal('true');
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });

    describe('populate', function() {
      it('should not populate a restricted field', function(done) {
        User.restricted.push('contacts');
        request(app).get('/users/Bob')
          .query({
            populate: 'contacts  '
          })
          .end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(401);
            expect(res.body.message).to.match(/Cannot populate restricted field/);
            done();
          });
      });

      it('should error if the field does not exist', function(done) {
        request(app).get('/users/Bob')
          .query({
            populate: 'dne'
          }).end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(400);
            expect(res.body.message).to.match(/does not exist/);
            done();
          });
      });

      it('should populate a field', function(done) {
        request(app).get('/users/Bob')
          .query({
            populate: 'contacts'
          }).end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(200);
            expect(res.body.contacts.length).to.equal(4);
            done();
          });
      });
    });
  });

  describe('update', function() {
    it('should change a field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .send({
          hobby: 'Basketball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.hobby).to.equal('Basketball');
          done();
        });
    });

    it('should not change a non-existent field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .send({
          dne: 'Basketball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.dne).to.be.undefined;
          done();
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).put('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should change a subdocument field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob/comments/BobL')
        .send({
          content: 'Android BobL is op'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Android BobL is op');
          done();
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob/comments/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "DNE" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.equal('true');
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });
  });

  describe('destroy', function() {
    it('should delete the document', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.success).to.be.true;
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, doc) {
            expect(doc).to.be.null;
            done();
          });
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).delete('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should delete the subdocument', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob/comments/BobL')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.success).to.be.true;
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            Comment.model.findOne({
              author: bob,
              reaction: 'BobL'
            }).exec(function(err, doc) {
              expect(doc).to.be.null;
              done();
            });
          });
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob/comments/X')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "X" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.equal('true');
          done();
        });
    });
  });
});
<commit_msg>fix tests<commit_after>'use strict';

var expect = require('chai').expect;
var express = require('express');
var http = require('http');
var mongoose = require('mongoose');
var request = require('supertest');
var async = require('async');

var setup = require('./setup');

describe('routes', function() {
  var app, conn, User, Comment;

  before(function() {
    conn = setup.models();
  });

  beforeEach(function(done) {
    var ret = setup.data(done);
    app = ret.app;
    User = ret.User;
    Comment = ret.Comment;
  });

  afterEach(function(done) {
    async.parallel([
      function(callback) {
        User.model.remove({}, callback);
      },
      function(callback) {
        Comment.model.remove({}, callback);
      }
    ], done);
  });

  after(function(done) {
    this.timeout(5000);
    conn.db.dropDatabase(function(err) {
      done(err);
    });
  });

  describe('create', function() {
    it('should create a document', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          name: 'Asdflol',
          hobby: 'Baseball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.id).to.equal('Asdflol');
          expect(res.body.name).to.equal('Asdflol');
          done();
        });
    });

    it('should 409 if the document already exists', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          name: 'Bob',
          hobby: 'Soccer'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(409);
          expect(res.body.message).to.match(/User already exists/);
          done();
        });
    });

    it('should create a subdocument', function(done) {
      User.id = 'name';
      request(app).post('/users/Bob/comments')
        .send({
          content: 'Test',
          reaction: 'asdf'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Test');
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            expect(res.body.author._id.toString()).to.equal(bob._id.toString());
            done();
          });
        });
    });

    it('should 409 if the subdocument already exists', function(done) {
      User.id = 'name';
      request(app).post('/users/Bob/comments')
        .send({
          content: 'exists',
          reaction: 'BobL'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(409);
          expect(res.body.message).to.match(/Comment already exists/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).post('/users')
        .send({
          name: 'Asdflol',
          hobby: 'Baseball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.equal('true');
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });
  });

  describe('get', function() {
    it('should get a document by id', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.name).to.equal('Bob');
          done();
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).get('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should get a subdocument by id', function(done) {
      User.id = 'name';
      Comment.id = 'reaction';
      request(app).get('/users/Bob/comments/BobL')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Lol');
          expect(res.body.reaction).to.equal('BobL');
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            expect(res.body.author).to.equal(bob._id.toString());
            done();
          });
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob/comments/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "DNE" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).get('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.equal('true');
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });

    describe('populate', function() {
      it('should not populate a restricted field', function(done) {
        User.restricted.push('contacts');
        request(app).get('/users/Bob')
          .query({
            populate: 'contacts  '
          })
          .end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(401);
            expect(res.body.message).to.match(/Cannot populate restricted field/);
            done();
          });
      });

      it('should error if the field does not exist', function(done) {
        request(app).get('/users/Bob')
          .query({
            populate: 'dne'
          }).end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(400);
            expect(res.body.message).to.match(/does not exist/);
            done();
          });
      });

      it('should populate a field', function(done) {
        request(app).get('/users/Bob')
          .query({
            populate: 'contacts'
          }).end(function(err, res) {
            expect(err).to.be.null;
            expect(res.status).to.equal(200);
            expect(res.body.contacts.length).to.equal(4);
            done();
          });
      });
    });
  });

  describe('update', function() {
    it('should change a field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .send({
          hobby: 'Basketball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.hobby).to.equal('Basketball');
          done();
        });
    });

    it('should not change a non-existent field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .send({
          dne: 'Basketball'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.dne).to.be.undefined;
          done();
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).put('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should change a subdocument field', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob/comments/BobL')
        .send({
          content: 'Android BobL is op'
        })
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.content).to.equal('Android BobL is op');
          done();
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob/comments/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "DNE" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).put('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.equal('true');
          expect(res.header['middleware-destroy']).to.be.undefined;
          done();
        });
    });
  });

  describe('destroy', function() {
    it('should delete the document', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.success).to.be.true;
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, doc) {
            expect(doc).to.be.null;
            done();
          });
        });
    });

    it('should 404 if the document was not found', function(done) {
      User.id = 'name';
      request(app).delete('/users/DNE')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/User "DNE" not found/);
          done();
        });
    });

    it('should delete the subdocument', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob/comments/BobL')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(200);
          expect(res.body.success).to.be.true;
          User.model.findOne({
            name: 'Bob'
          }).exec(function(err, bob) {
            Comment.model.findOne({
              author: bob,
              reaction: 'BobL'
            }).exec(function(err, doc) {
              expect(doc).to.be.null;
              done();
            });
          });
        });
    });

    it('should 404 if the subdocument was not found', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob/comments/X')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.status).to.equal(404);
          expect(res.body.message).to.match(/Comment "X" not found/);
          done();
        });
    });

    it('should have used appropriate middlewares', function(done) {
      User.id = 'name';
      request(app).delete('/users/Bob')
        .end(function(err, res) {
          expect(err).to.be.null;
          expect(res.header['middleware-all']).to.equal('true');
          expect(res.header['middleware-query']).to.be.undefined;
          expect(res.header['middleware-create']).to.be.undefined;
          expect(res.header['middleware-get']).to.be.undefined;
          expect(res.header['middleware-update']).to.be.undefined;
          expect(res.header['middleware-destroy']).to.equal('true');
          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	if(!OC.Share) {
		OC.Share = {};
	}

	var TEMPLATE_BASE =
		'

' +
		'{{#if isSharingAllowed}}' +
		'{{shareLabel}}' +
		'
' +
		'    <input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{sharePlaceholder}}" />' +
		'    '+
		'{{{remoteShareInfo}}}' +
		'
' +
		'{{/if}}' +
		'

' +
		'

' +
		'

' +
		'

';

	var TEMPLATE_REMOTE_SHARE_INFO =
		'';

	/**
	 * @class OCA.Share.ShareDialogView
	 * @member {OC.Share.ShareItemModel} model
	 * @member {jQuery} $el
	 * @memberof OCA.Sharing
	 * @classdesc
	 *
	 * Represents the GUI of the share dialogue
	 *
	 */
	var ShareDialogView = OC.Backbone.View.extend({
		/** @type {Object} **/
		_templates: {},

		/** @type {boolean} **/
		_showLink: true,

		/** @type {string} **/
		tagName: 'div',

		/** @type {OC.Share.ShareConfigModel} **/
		configModel: undefined,

		/** @type {object} **/
		resharerInfoView: undefined,

		/** @type {object} **/
		linkShareView: undefined,

		/** @type {object} **/
		expirationView: undefined,

		/** @type {object} **/
		shareeListView: undefined,

		initialize: function(options) {
			var view = this;

			this.model.on('fetchError', function() {
				OC.Notification.showTemporary(t('core', 'Share details could not be loaded for this item.'));
			});

			if(!_.isUndefined(options.configModel)) {
				this.configModel = options.configModel;
			} else {
				throw 'missing OC.Share.ShareConfigModel';
			}

			this.configModel.on('change:isRemoteShareAllowed', function() {
				view.render();
			});
			this.model.on('change:permissions', function() {
				view.render();
			});

			this.model.on('request', this._onRequest, this);
			this.model.on('sync', this._onEndRequest, this);

			var subViewOptions = {
				model: this.model,
				configModel: this.configModel
			};

			var subViews = {
				resharerInfoView: 'ShareDialogResharerInfoView',
				linkShareView: 'ShareDialogLinkShareView',
				expirationView: 'ShareDialogExpirationView',
				shareeListView: 'ShareDialogShareeListView'
			};

			for(var name in subViews) {
				var className = subViews[name];
				this[name] = _.isUndefined(options[name])
					? new OC.Share[className](subViewOptions)
					: options[name];
			}

			_.bindAll(this, 'autocompleteHandler', '_onSelectRecipient');
		},

		autocompleteHandler: function (search, response) {
			var view = this;
			var $loading = this.$el.find('.shareWithLoading');
			$loading.removeClass('hidden');
			$loading.addClass('inlineblock');
			$.get(
				OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
				{
					format: 'json',
					search: search.term.trim(),
					perPage: 200,
					itemType: view.model.get('itemType')
				},
				function (result) {
					$loading.addClass('hidden');
					$loading.removeClass('inlineblock');
					if (result.ocs.meta.statuscode == 100) {
						var users   = result.ocs.data.exact.users.concat(result.ocs.data.users);
						var groups  = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
						var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);

						var usersLength;
						var groupsLength;
						var remotesLength;

						var i, j;

						//Filter out the current user
						usersLength = users.length;
						for (i = 0 ; i < usersLength; i++) {
							if (users[i].value.shareWith === OC.currentUser) {
								users.splice(i, 1);
								break;
							}
						}

						// Filter out the owner of the share
						if (view.model.hasReshare()) {
							usersLength = users.length;
							for (i = 0 ; i < usersLength; i++) {
								if (users[i].value.shareWith === view.model.getReshareOwner()) {
									users.splice(i, 1);
									break;
								}
							}
						}

						var shares = view.model.get('shares');
						var sharesLength = shares.length;

						// Now filter out all sharees that are already shared with
						for (i = 0; i < sharesLength; i++) {
							var share = shares[i];

							if (share.share_type === OC.Share.SHARE_TYPE_USER) {
								usersLength = users.length;
								for (j = 0; j < usersLength; j++) {
									if (users[j].value.shareWith === share.share_with) {
										users.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
								groupsLength = groups.length;
								for (j = 0; j < groupsLength; j++) {
									if (groups[j].value.shareWith === share.share_with) {
										groups.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
								remotesLength = remotes.length;
								for (j = 0; j < remotesLength; j++) {
									if (remotes[j].value.shareWith === share.share_with) {
										remotes.splice(j, 1);
										break;
									}
								}
							}
						}

						var suggestions = users.concat(groups).concat(remotes);

						if (suggestions.length > 0) {
							$('.shareWithField').autocomplete("option", "autoFocus", true);
							response(suggestions);
						} else {
							response();
						}
					} else {
						response();
					}
				}
			).fail(function() {
				$loading.addClass('hidden');
				$loading.removeClass('inlineblock');
				OC.Notification.show(t('core', 'An error occured. Please try again'));
				window.setTimeout(OC.Notification.hide, 5000);
			});
		},

		autocompleteRenderItem: function(ul, item) {
			var insert = $("");
			var text = item.label;
			if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
				text = text +  ' ('+t('core', 'group')+')';
			} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
				text = text +  ' ('+t('core', 'remote')+')';
			}
			insert.text(text);
			if(item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
				insert = insert.wrapInner('');
			}
			return $("
")
				.addClass((item.value.shareType === OC.Share.SHARE_TYPE_GROUP) ? 'group' : 'user')
				.append(insert)
				.appendTo(ul);
		},

		_onSelectRecipient: function(e, s) {
			e.preventDefault();
			$(e.target).val('');
			this.model.addShare(s.item.value);
		},

		_toggleLoading: function(state) {
			this._loading = state;
			this.$el.find('.subView').toggleClass('hidden', state);
			this.$el.find('.loading').toggleClass('hidden', !state);
		},

		_onRequest: function() {
			// only show the loading spinner for the first request (for now)
			if (!this._loadingOnce) {
				this._toggleLoading(true);
			}
		},

		_onEndRequest: function() {
			var self = this;
			this._toggleLoading(false);
			if (!this._loadingOnce) {
				this._loadingOnce = true;
				// the first time, focus on the share field after the spinner disappeared
				_.defer(function() {
					self.$('.shareWithField').focus();
				});
			}
		},

		render: function() {
			var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);

			this.$el.html(baseTemplate({
				cid: this.cid,
				shareLabel: t('core', 'Share'),
				sharePlaceholder: this._renderSharePlaceholderPart(),
				remoteShareInfo: this._renderRemoteShareInfoPart(),
				isSharingAllowed: this.model.sharePermissionPossible()
			}));

			var $shareField = this.$el.find('.shareWithField');
			if ($shareField.length) {
				$shareField.autocomplete({
					minLength: 2,
					delay: 750,
					focus: function(event) {
						event.preventDefault();
					},
					source: this.autocompleteHandler,
					select: this._onSelectRecipient
				}).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem;
			}

			this.resharerInfoView.$el = this.$el.find('.resharerInfoView');
			this.resharerInfoView.render();

			this.linkShareView.$el = this.$el.find('.linkShareView');
			this.linkShareView.render();

			this.expirationView.$el = this.$el.find('.expirationView');
			this.expirationView.render();

			this.shareeListView.$el = this.$el.find('.shareeListView');
			this.shareeListView.render();

			this.$el.find('.hasTooltip').tooltip();

			return this;
		},

		/**
		 * sets whether share by link should be displayed or not. Default is
		 * true.
		 *
		 * @param {bool} showLink
		 */
		setShowLink: function(showLink) {
			this._showLink = (typeof showLink === 'boolean') ? showLink : true;
			this.linkShareView.showLink = this._showLink;
		},

		_renderRemoteShareInfoPart: function() {
			var remoteShareInfo = '';
			if(this.configModel.get('isRemoteShareAllowed')) {
				var infoTemplate = this._getRemoteShareInfoTemplate();
				remoteShareInfo = infoTemplate({
					docLink: this.configModel.getFederatedShareDocLink(),
					tooltip: t('core', 'Share with people on other ownClouds using the syntax username@example.com/owncloud')
				});
			}

			return remoteShareInfo;
		},

		_renderSharePlaceholderPart: function () {
			var sharePlaceholder = t('core', 'Share with users or groups …');
			if (this.configModel.get('isRemoteShareAllowed')) {
				sharePlaceholder = t('core', 'Share with users, groups or remote users …');
			}
			return sharePlaceholder;
		},

		/**
		 *
		 * @param {string} key - an identifier for the template
		 * @param {string} template - the HTML to be compiled by Handlebars
		 * @returns {Function} from Handlebars
		 * @private
		 */
		_getTemplate: function (key, template) {
			if (!this._templates[key]) {
				this._templates[key] = Handlebars.compile(template);
			}
			return this._templates[key];
		},

		/**
		 * returns the info template for remote sharing
		 *
		 * @returns {Function}
		 * @private
		 */
		_getRemoteShareInfoTemplate: function() {
			return this._getTemplate('remoteShareInfo', TEMPLATE_REMOTE_SHARE_INFO);
		}
	});

	OC.Share.ShareDialogView = ShareDialogView;

})();
<commit_msg>show remote server on auto complete<commit_after>/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	if(!OC.Share) {
		OC.Share = {};
	}

	var TEMPLATE_BASE =
		'

' +
		'{{#if isSharingAllowed}}' +
		'{{shareLabel}}' +
		'
' +
		'    <input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{sharePlaceholder}}" />' +
		'    '+
		'{{{remoteShareInfo}}}' +
		'
' +
		'{{/if}}' +
		'

' +
		'

' +
		'

' +
		'

';

	var TEMPLATE_REMOTE_SHARE_INFO =
		'';

	/**
	 * @class OCA.Share.ShareDialogView
	 * @member {OC.Share.ShareItemModel} model
	 * @member {jQuery} $el
	 * @memberof OCA.Sharing
	 * @classdesc
	 *
	 * Represents the GUI of the share dialogue
	 *
	 */
	var ShareDialogView = OC.Backbone.View.extend({
		/** @type {Object} **/
		_templates: {},

		/** @type {boolean} **/
		_showLink: true,

		/** @type {string} **/
		tagName: 'div',

		/** @type {OC.Share.ShareConfigModel} **/
		configModel: undefined,

		/** @type {object} **/
		resharerInfoView: undefined,

		/** @type {object} **/
		linkShareView: undefined,

		/** @type {object} **/
		expirationView: undefined,

		/** @type {object} **/
		shareeListView: undefined,

		initialize: function(options) {
			var view = this;

			this.model.on('fetchError', function() {
				OC.Notification.showTemporary(t('core', 'Share details could not be loaded for this item.'));
			});

			if(!_.isUndefined(options.configModel)) {
				this.configModel = options.configModel;
			} else {
				throw 'missing OC.Share.ShareConfigModel';
			}

			this.configModel.on('change:isRemoteShareAllowed', function() {
				view.render();
			});
			this.model.on('change:permissions', function() {
				view.render();
			});

			this.model.on('request', this._onRequest, this);
			this.model.on('sync', this._onEndRequest, this);

			var subViewOptions = {
				model: this.model,
				configModel: this.configModel
			};

			var subViews = {
				resharerInfoView: 'ShareDialogResharerInfoView',
				linkShareView: 'ShareDialogLinkShareView',
				expirationView: 'ShareDialogExpirationView',
				shareeListView: 'ShareDialogShareeListView'
			};

			for(var name in subViews) {
				var className = subViews[name];
				this[name] = _.isUndefined(options[name])
					? new OC.Share[className](subViewOptions)
					: options[name];
			}

			_.bindAll(this, 'autocompleteHandler', '_onSelectRecipient');
		},

		autocompleteHandler: function (search, response) {
			var view = this;
			var $loading = this.$el.find('.shareWithLoading');
			$loading.removeClass('hidden');
			$loading.addClass('inlineblock');
			$.get(
				OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
				{
					format: 'json',
					search: search.term.trim(),
					perPage: 200,
					itemType: view.model.get('itemType')
				},
				function (result) {
					$loading.addClass('hidden');
					$loading.removeClass('inlineblock');
					if (result.ocs.meta.statuscode == 100) {
						var users   = result.ocs.data.exact.users.concat(result.ocs.data.users);
						var groups  = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
						var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);

						var usersLength;
						var groupsLength;
						var remotesLength;

						var i, j;

						//Filter out the current user
						usersLength = users.length;
						for (i = 0 ; i < usersLength; i++) {
							if (users[i].value.shareWith === OC.currentUser) {
								users.splice(i, 1);
								break;
							}
						}

						// Filter out the owner of the share
						if (view.model.hasReshare()) {
							usersLength = users.length;
							for (i = 0 ; i < usersLength; i++) {
								if (users[i].value.shareWith === view.model.getReshareOwner()) {
									users.splice(i, 1);
									break;
								}
							}
						}

						var shares = view.model.get('shares');
						var sharesLength = shares.length;

						// Now filter out all sharees that are already shared with
						for (i = 0; i < sharesLength; i++) {
							var share = shares[i];

							if (share.share_type === OC.Share.SHARE_TYPE_USER) {
								usersLength = users.length;
								for (j = 0; j < usersLength; j++) {
									if (users[j].value.shareWith === share.share_with) {
										users.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
								groupsLength = groups.length;
								for (j = 0; j < groupsLength; j++) {
									if (groups[j].value.shareWith === share.share_with) {
										groups.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
								remotesLength = remotes.length;
								for (j = 0; j < remotesLength; j++) {
									if (remotes[j].value.shareWith === share.share_with) {
										remotes.splice(j, 1);
										break;
									}
								}
							}
						}

						var suggestions = users.concat(groups).concat(remotes);

						if (suggestions.length > 0) {
							$('.shareWithField').autocomplete("option", "autoFocus", true);
							response(suggestions);
						} else {
							response();
						}
					} else {
						response();
					}
				}
			).fail(function() {
				$loading.addClass('hidden');
				$loading.removeClass('inlineblock');
				OC.Notification.show(t('core', 'An error occured. Please try again'));
				window.setTimeout(OC.Notification.hide, 5000);
			});
		},

		autocompleteRenderItem: function(ul, item) {
			var insert = $("");
			var text = item.label;
			if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
				text = text +  ' ('+t('core', 'group')+')';
			} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
				if (item.value.server) {
					text = text + ' (' + t('core', 'at') + ' ' + item.value.server + ')';
				} else {
					text = text + ' (' + t('core', 'remote') + ')';
				}
			}
			insert.text(text);
			if(item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
				insert = insert.wrapInner('');
			}
			return $("
")
				.addClass((item.value.shareType === OC.Share.SHARE_TYPE_GROUP) ? 'group' : 'user')
				.append(insert)
				.appendTo(ul);
		},

		_onSelectRecipient: function(e, s) {
			e.preventDefault();
			$(e.target).val('');
			this.model.addShare(s.item.value);
		},

		_toggleLoading: function(state) {
			this._loading = state;
			this.$el.find('.subView').toggleClass('hidden', state);
			this.$el.find('.loading').toggleClass('hidden', !state);
		},

		_onRequest: function() {
			// only show the loading spinner for the first request (for now)
			if (!this._loadingOnce) {
				this._toggleLoading(true);
			}
		},

		_onEndRequest: function() {
			var self = this;
			this._toggleLoading(false);
			if (!this._loadingOnce) {
				this._loadingOnce = true;
				// the first time, focus on the share field after the spinner disappeared
				_.defer(function() {
					self.$('.shareWithField').focus();
				});
			}
		},

		render: function() {
			var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);

			this.$el.html(baseTemplate({
				cid: this.cid,
				shareLabel: t('core', 'Share'),
				sharePlaceholder: this._renderSharePlaceholderPart(),
				remoteShareInfo: this._renderRemoteShareInfoPart(),
				isSharingAllowed: this.model.sharePermissionPossible()
			}));

			var $shareField = this.$el.find('.shareWithField');
			if ($shareField.length) {
				$shareField.autocomplete({
					minLength: 2,
					delay: 750,
					focus: function(event) {
						event.preventDefault();
					},
					source: this.autocompleteHandler,
					select: this._onSelectRecipient
				}).data('ui-autocomplete')._renderItem = this.autocompleteRenderItem;
			}

			this.resharerInfoView.$el = this.$el.find('.resharerInfoView');
			this.resharerInfoView.render();

			this.linkShareView.$el = this.$el.find('.linkShareView');
			this.linkShareView.render();

			this.expirationView.$el = this.$el.find('.expirationView');
			this.expirationView.render();

			this.shareeListView.$el = this.$el.find('.shareeListView');
			this.shareeListView.render();

			this.$el.find('.hasTooltip').tooltip();

			return this;
		},

		/**
		 * sets whether share by link should be displayed or not. Default is
		 * true.
		 *
		 * @param {bool} showLink
		 */
		setShowLink: function(showLink) {
			this._showLink = (typeof showLink === 'boolean') ? showLink : true;
			this.linkShareView.showLink = this._showLink;
		},

		_renderRemoteShareInfoPart: function() {
			var remoteShareInfo = '';
			if(this.configModel.get('isRemoteShareAllowed')) {
				var infoTemplate = this._getRemoteShareInfoTemplate();
				remoteShareInfo = infoTemplate({
					docLink: this.configModel.getFederatedShareDocLink(),
					tooltip: t('core', 'Share with people on other ownClouds using the syntax username@example.com/owncloud')
				});
			}

			return remoteShareInfo;
		},

		_renderSharePlaceholderPart: function () {
			var sharePlaceholder = t('core', 'Share with users or groups …');
			if (this.configModel.get('isRemoteShareAllowed')) {
				sharePlaceholder = t('core', 'Share with users, groups or remote users …');
			}
			return sharePlaceholder;
		},

		/**
		 *
		 * @param {string} key - an identifier for the template
		 * @param {string} template - the HTML to be compiled by Handlebars
		 * @returns {Function} from Handlebars
		 * @private
		 */
		_getTemplate: function (key, template) {
			if (!this._templates[key]) {
				this._templates[key] = Handlebars.compile(template);
			}
			return this._templates[key];
		},

		/**
		 * returns the info template for remote sharing
		 *
		 * @returns {Function}
		 * @private
		 */
		_getRemoteShareInfoTemplate: function() {
			return this._getTemplate('remoteShareInfo', TEMPLATE_REMOTE_SHARE_INFO);
		}
	});

	OC.Share.ShareDialogView = ShareDialogView;

})();
<|endoftext|>


<commit_before>var seneca = require('seneca')()

seneca.add('role:v1,cmd:caz',function(args,done){
  done(null,{caz:args.q+' ANALYSE '})
})

seneca.add('role:foo,cmd:bar',function(args,done){
  done(null,{bar:args.zoo+'b'})
})

seneca.add('role:foo,cmd:qaz',function(args,done){
  done(null,{qaz:args.zoo+'z'})
})

seneca.act('role:web',{use:{
  prefix:'/foo',
  pin:{role:'foo',cmd:'*'},
  map:{
    zig: true,
    bar: {GET:true},
    qaz: {GET:true,HEAD:true}
  }
}})

seneca.listen()

var connect = require('connect')
var app = connect()
app.use( connect.query() )
app.use( seneca.export('web') )
app.listen(3000)

// run: node test/example.js --seneca.log=type:act
// try http://localhost:3000/foo/bar?zoo=a
// returns {"bar":"ab"}
<commit_msg>add http.get<commit_after>var seneca = require('seneca')();
var http = require('http');

seneca.add('role:foo,cmd:bar',function(args,done){

  /*
   * https://dandelion.eu/products/datatxt/nex/demo/?text=The+Mona+Lisa+is+a+16th+century+oil+painting+created+by+Leonardo.+It%27s+held+at+the+Louvre+in+Paris.&lang=auto&min_confidence=0.6&exec=true#results
   *
   * */

  http.get("http://www.cuisineaz.com", function(res) {
	  console.log("Got response: " + res.statusCode+"   args:"+args.q);
	}).on('error', function(e) {
	  console.log("Got error: " + e.message);
	});

  done(null,{bar:args.q+'b ok'})

})

seneca.add('role:foo,cmd:qaz',function(args,done){
  done(null,{qaz:args.zoo+' zaaa'})
})

seneca.act('role:web',{use:{
  prefix:'/foo',
  pin:{role:'foo',cmd:'*'},
  map:{
    zig: true,
    bar: {GET:true},
    qaz: {GET:true,HEAD:true}
  }
}})

seneca.listen()

var connect = require('connect')
var app = connect()
app.use( connect.query() )
app.use( seneca.export('web') )
app.listen(3000)

// run: node test/example.js --seneca.log=type:act
// try http://localhost:3000/foo/bar?zoo=a
// returns {"bar":"ab"}
<|endoftext|>


<commit_before>'use strict'

$(function () {
  $('#finish').bind('click', saveSettings);

  $("#save-personal-data").bind('click', saveData(["name"]));
  $("#save-travel-data").bind('click', saveData(["vacDays", "budget", "distance", "travelMode"]));
  $("#save-important-information").bind('click', saveData(["favDestination", "kids", "adults", "dog"]));

  hoodie.store.findOrAdd('settings', "user-settings", {})
  .done(function(settings) {
    setData(settings)
  })
})

var saveData = function(args) {
  return function() {
    var self = $(this);
    var success = self.siblings(".save-success");

    var updatedData = {}
    $.each(args, function(i,arg) {
      updatedData[arg] = val(arg);
    });

    hoodie.store.update('settings', "user-settings", updatedData)
    .done(function(settings) {
      success.toggleClass("hidden")
      setTimeout(function() {
        success.toggleClass("hidden")
      }, 2000);
    })

    return false;
  }
}

function val(id, value) {
  if (value) {
      $("#"+id).val(value);
  } else {
      return $("#"+id).val();
  }
}
function getData() {
  return {
    name:        val("name"),

    vacDays:     val("vacDays"),
    budget:      val("budget"),
    distance:    val("distance"),
    travelMode:  val("travelMode"),

    favDestination: val("favDestination"),
    kids:    val("kids"),
    adults:  val("adults"),
    dog:     val("dog")
  };
}
function setData(settings) {
  val("name", settings.name),

  val("vacDays", settings.vacDays),
  val("budget", settings.budget),
  val("distance", settings.distance),
  val("travelMode", settings.travelMode),

  val("favDestination", settings.favDestination),
  val("kids", settings.kids),
  val("adults", settings.adults),
  val("dog", settings.dog)
}

var saveSettings = function saveSettings(e) {
  e.preventDefault();

  var data = getData();

  hoodie.store.findOrAdd('settings', "user-settings", {})
  .done(function(obj) {
    hoodie.store.update('settings', "user-settings", data)
    .done(function(settings) {
      location.href = "dashboard.html";
    })
    .fail(function(err) {
      alert("Something went wrong saving your settings.");
    });
  })

  return false;
}
<commit_msg>fix: store daterange values<commit_after>'use strict'

$(function () {
  $('#finish').bind('click', saveSettings);

  $("#save-personal-data").bind('click', saveData(["name"]));
  $("#save-travel-data").bind('click', saveData(["vacDays", "budget", "distance", "travelMode"]));
  $("#save-important-information").bind('click', saveData(["favDestination", "kids", "adults", "dog"]));

  hoodie.store.findOrAdd('settings', "user-settings", {})
  .done(function(settings) {
    setData(settings)
  })
})

var saveData = function(args) {
  return function() {
    var self = $(this);
    var success = self.siblings(".save-success");

    var updatedData = {}
    $.each(args, function(i,arg) {
      updatedData[arg] = val(arg);
    });

    // HACK
    updatedData['daterange-vacation'] = $('[name="daterange-vacation[]"]').map(function(){return $(this).val();}).get();
    updatedData['daterange-work'] = $('[name="daterange-work[]"]').map(function(){return $(this).val();}).get();

    hoodie.store.update('settings', "user-settings", updatedData)
    .done(function(settings) {
      success.toggleClass("hidden")
      setTimeout(function() {
        success.toggleClass("hidden")
      }, 2000);
    })

    return false;
  }
}

function val(id, value) {
  if (value) {
      $("#"+id).val(value);
  } else {
      return $("#"+id).val();
  }
}
function getData() {
  return {
    name:        val("name"),

    vacDays:     val("vacDays"),
    budget:      val("budget"),
    distance:    val("distance"),
    travelMode:  val("travelMode"),

    favDestination: val("favDestination"),
    kids:    val("kids"),
    adults:  val("adults"),
    dog:     val("dog")
  };
}
function setData(settings) {
  val("name", settings.name),

  val("vacDays", settings.vacDays),
  val("budget", settings.budget),
  val("distance", settings.distance),
  val("travelMode", settings.travelMode),

  val("favDestination", settings.favDestination),
  val("kids", settings.kids),
  val("adults", settings.adults),
  val("dog", settings.dog)
}

var saveSettings = function saveSettings(e) {
  e.preventDefault();

  var data = getData();

  hoodie.store.findOrAdd('settings', "user-settings", {})
  .done(function(obj) {
    hoodie.store.update('settings', "user-settings", data)
    .done(function(settings) {
      location.href = "dashboard.html";
    })
    .fail(function(err) {
      alert("Something went wrong saving your settings.");
    });
  })

  return false;
}
<|endoftext|>