Files
JMuseum/models/mongooseSchemas/Season.js
2018-02-26 14:09:18 +08:00

169 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ServerStatus = require("../../ServerStatus");
const Theme = require("./Theme");
const NewTheme = require("./NewTheme");
/**
* 回呼函式。
* @callback CallbackFunction
* @param {Object} err 錯誤資訊物件。
* @param {Object} obj 傳回的物件。
*/
/**
* 「季」的模板定義。
* @prop {number} nth 表示目前的資料是第nth季
* @prop {Schema.Types.ObjectId[]} themes 這一季的所有主題。
* @prop {Date} startTime 這一季的開始時間。
* @prop {Date} endTime 這一季的結束時間。
*/
let SeasonSchema = Schema({
nth: Number,
themes: [{type : Schema.Types.ObjectId, ref : "Theme"}],
startTime: {type : Date, default : Date.now},
endTime: Date
});
/**
* 新一季的必要的基本資料。
* @typedef NewSeasonData
* @prop {number} nth 紀錄此資料為第nth季。
* @prop {ObjectId[]} themes 這一季所有的活動。以ObjectId做關聯。
* @prop {Date} startTime 開始這一季時的時間。
*/
/**
* 建立一個新的「季」資料。
* @param {Object} data 欲儲存的原始資料。
* @param {function} callback 回呼函式(Error, ObjectId)。
*/
SeasonSchema.statics.createNewSeason = function (data, callback) {
let newSeason = this({
nth: data.nth,
themes: data.themes,
startTime: data.startTime,
endTime: null
});
newSeason.save((err, season) => {
if (err) return callback(err, null);
callback(null, season._id);
});
}
/**
* 取得「傑作藝廊」頁面所需的資料。
* 注意: 要取用相關資料時必須先將Theme與ParticipantInfo資料表引入。
* @param {CallbackFunction} callback 回呼函式。含有錯誤訊息物件或資料物件。
*/
SeasonSchema.statics.GetGalleryNeedInfo = function (callback) {
// 取得一季之中所有的「主題 (themes)」與「季次 (nth)」
// 所有主題中的「編號 (order)」、「標題 (title)」與「參加作品 (participants)」
// 參加作品中的「排行 (rank)」、「作者 (artist)」、「作品敘述 (description)」與「投稿時間 (postTime)」
let curNthSeason = ServerStatus.status.currentSeason;
let populateQuery = {
path : "themes",
select : {"order": 1, "title": 1, "participants": 1},
populate : {
path : "participants",
select : {"rank": 1, "artist": 1, "description": 1, "postTime": 1}
}
};
// {"nth": {$lt: curNthSeason}} 中的 $lt: curNthSeason 表示不要選取到最新一季。
this.find({"nth": {$lt: curNthSeason}}).sort({nth: -1}).select("nth themes").populate(populateQuery).exec(callback);
}
/**
* 取得在「畫作主題」頁面下所需要的插值資料。
* @param {CallbackFunction} callback 回呼函式。含有錯誤訊息物件或資料物件。
*/
SeasonSchema.statics.GetThemePageNeedInfo = function (callback) {
let result = {currentSeason: null, lastSeason: null};
let currentSeasonPopulate = {path: "themes", select: {"order": 1, "title": 1, "narrative": 1, "imageURL": 1, "originator": 1, "participentCount": 1, "views": 1, "commentCount": 1}};
let lastSeasonPopulate = {path: "themes", select: {"order": 1, "title": 1, "originator": 1}};
let currentNthSeason = ServerStatus.status.currentSeason;
// 以nth尋找最新的一季在選擇其中的「nth」與「themes」欄位
// 並對「themes」展開選擇其中的指定欄位然後執行以上動作。
this.findOne({"nth": currentNthSeason})
.select("nth themes")
.populate(currentSeasonPopulate)
.exec((err, curSeason) => {
if (err) {
callback(err, null);
return;
}
result.currentSeason = curSeason;
// 接著尋找上一季指定「nth」、「endTime」與「themes」欄位
// 並對「themes」展開選擇其中的指定欄位然後執行以上動作。
this.findOne({"nth": currentNthSeason - 1})
.select("nth endTime themes")
.populate(lastSeasonPopulate)
.exec((err, lastSeason) => {
if (err) {
callback(err, null);
return;
}
result.lastSeason = lastSeason;
callback(null, result);
return;
});
});
}
/**
* 將畫作主題活動推進新的一季。
* 注意ServerStatus.status中的currentSeason必須要先推進到新的一季否則會相衝。
* @param {CallbackFunction} callback 回呼函式。
*/
SeasonSchema.statics.PushNewSeason = function (callback) {
let promotionCount = ServerStatus.status.promotionCount; // 取得要選取多少個候選主題至正規主題中
let curNthSeason = ServerStatus.status.currentSeason;
let Season = this;
// 首先先更新上一季的結束時間
Season.update({ nth: curNthSeason - 1 }, { $set: { "endTime": new Date() } }, (err, seasonDocs) => {
if(err) return callback(err, "\n更新前一季的時間時\n");
});
// 做統合取NewTheme中所有的欄位並建立一個 "voteCount" 欄位來記錄 votes 中有有多少個項目
// 然後再先後以投票數量(voteCount)與投稿時間(createdTime)來做排序並選取前N個(promotionCount)作為新一季的新主題。
NewTheme.aggregate(
[
{ "$project": {
title: 1,
narrative: 1,
image: 1,
sponsor: 1,
votes: 1,
createdTime: 1,
voteCount: { "$size": "$votes" }
}},
{ "$sort": { "voteCount": -1 } },
{ "$sort": { "createdTime": 1 } },
{ "$limit": promotionCount }
],
function (err, docsList) {
if (err) return callback(err, "\n取得指定候選主題時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
// 將指定的候選主題轉換到正規的主題(Theme)中。其中處理完成後回呼_id清單。
Theme.TransferFromNewTheme(docsList, (err, _idList) => {
if (err) return callback(err, "\n將候選主題轉換至正規主題時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
// 建立基本新的一季(Season)的資料
let data = {
nth: ServerStatus.status.currentSeason,
themes: _idList,
startTime: new Date()
};
// 利用data建立最新一季的資料
Season.createNewSeason(data, (err, _id) => {
if (err) return callback(err, "\n建立新一季的活動資料時發生了錯誤。請確認是否有連接MongoDB並重新嘗試。\n");
// 將所有的候選主題都清空
NewTheme.remove({}, (err) => {
if (err) return callback(err, "\n在清空NewTheme中所有資料時發生了錯誤。請改用手動的方式刪除或檢查是否有連接MongoDB。\n");
callback(null, true);
});
});
});
}
)
}
module.exports = mongoose.model("Season", SeasonSchema);