Skip to content

Instantly share code, notes, and snippets.

@RomanSteinberg
Created July 18, 2018 15:51
Show Gist options
  • Save RomanSteinberg/618b6b1d13e8d3cff7743b7dace818b0 to your computer and use it in GitHub Desktop.
Save RomanSteinberg/618b6b1d13e8d3cff7743b7dace818b0 to your computer and use it in GitHub Desktop.
models/task.js
const Promise = require('bluebird');
const mongoose = require('mongoose');
const _ = require('lodash');
const Answer = require('./answer');
const GooGl = require('./goo-gl');
const Meta = require('./meta');
const Recommendations = require('./recommendations');
const config = require('../config');
const helpers = require('../libs/helpers');
const STATUS_PENDING = 'pending';
const STATUS_FULFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';
const LOCALES = ['en', 'ru'];
const QUALITIES = ['bad', 'regular', 'good'];
const logger = require('../libs/logger.js');
const TaskSchema = new mongoose.Schema({
url: {
type: String,
required: true,
},
locale: {
type: String,
required: true,
},
parserTaskId: {
type: mongoose.Schema.ObjectId,
required: true,
},
uuid: {
type: String,
required: true,
},
status: {
type: String,
enum: [STATUS_PENDING, STATUS_FULFILLED, STATUS_REJECTED],
default: STATUS_PENDING,
required: true,
},
stages: {
type: [String],
required: true,
},
stage: {
type: String,
validate(stage) {
return this.stages.includes(stage);
},
required: true,
},
attributes: Object,
rate: Number,
recommendations: Object,
screenshot: String,
preview: String,
dateDone: Date,
error: String,
});
TaskSchema.statics = {
STATUS_PENDING,
STATUS_FULFILLED,
STATUS_REJECTED,
async getNewWithUuid({
url,
locale,
stages,
parserTaskId,
}, uuid) {
if (! helpers.url.validate(url)) throw new Error('Bad url');
url = helpers.url.normalise(url);
const task = await this.create({
url,
locale,
parserTaskId,
stages,
stage: stages[0],
uuid,
});
return task;
},
async getById(id) {
const task = await this.findById(id);
if (! task) {
throw new Error('Task not found');
}
return task;
},
async getByIdWithUuid(id, uuid) {
const task = await this.getById(id);
if (config.history.private && task.uuid !== uuid) {
throw new Error('Try access to task without owning it');
}
return task;
},
async getHistoryWithUuid({ from, to }, uuid) {
const tasksFilter = {
status: 'fulfilled',
};
if (config.history.private) {
tasksFilter.uuid = uuid;
}
let tasks = await this
.find(tasksFilter)
.sort({ _id: -1 })
.exec();
tasks = Object.values(_.groupBy(tasks, 'url'))
.map(tasks => tasks[0])
.slice(from, to);
return tasks;
},
getMeta(lang) {
return Meta.get(lang);
},
};
TaskSchema.methods = {
async setStages(stages) {
this.stages = stages;
await this.save();
return this;
},
async setStage(stage) {
logger.info('taskId=' + task.id + '; url=' + task.url + '; error=' + this.error + '; setStage=' + stage.toString());
this.stage = stage;
await this.save();
return this;
},
async setParserResult({ attributes, screenshot, preview }) {
logger.info('taskId=' + task.id + '; url=' + task.url + '; error=' + this.error + '; setParserResult done');
this.attributes = attributes;
this.screenshot = screenshot;
this.preview = preview;
await this.save();
return this;
},
async setModelResult(modelTask) {
logger.info('taskId=' + task.id + '; url=' + task.url + '; error=' + this.error + '; setModelResult done');
this.rate = modelTask.rate;
this.recommendations = modelTask.recommendations;
await this.save();
return this;
},
async setDone() {
this.status = STATUS_FULFILLED;
this.dateDone = Date.now();
await this.save();
return this;
},
async setError(message) {
this.status = STATUS_REJECTED;
this.error = message;
await this.save();
return this;
},
async serialize(uuid) {
let answer = null;
try {
({ rate: answer } = await Answer.getByTaskId(this.id, uuid));
} catch (err) {}
const meta = _.fromPairs(LOCALES.map(locale => [locale, this.getMeta(locale)]));
const shortUrl = _.fromPairs(await Promise.map(LOCALES, async locale => [locale, await GooGl.getShortUrl(meta[locale].ogUrl.content)]));
const recommendations = this.rate < config.rate.recommendationsThreshold ?
_.fromPairs(LOCALES.map(locale => [locale, this.getRecommendations(locale)])) :
_.fromPairs(LOCALES.map(locale => [locale, []]));
const quality = QUALITIES[_.sortedIndex(config.rate.qualityThreshold, this.rate)];
return {
..._.pick(this, [
'id',
'url',
'status',
'stages',
'stage',
'rate',
'dateDone',
'error',
]),
answer,
meta,
shortUrl,
recommendations,
quality,
};
},
getMeta(locale) {
return Meta.get(locale, 'task', {
title: { rate: Math.round(this.rate) },
url: { taskId: this.id },
image: { taskId: this.id },
});
},
getRecommendations(locale) {
return Recommendations.get({
locale,
attributes: this.attributes,
recommendations: this.recommendations,
});
},
};
module.exports = mongoose.model('Task', TaskSchema);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment