Added holiday picker

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-11-25 14:52:53 -08:00
parent 63e44c5ad3
commit 182606db20
6 changed files with 245 additions and 46 deletions

View File

@ -304,6 +304,15 @@
#requestAccess #createButton {
margin-top: 1.5em;
}
#holiday > div:first-child {
font-weight: bold;
}
#holiday [tabindex]:hover {
text-decoration: underline;
cursor: pointer;
}
</style>
<app-location route="{{route}}"></app-location>
@ -314,12 +323,18 @@
<!--paper-tab tab="time"><paper-icon-button icon="date-range"></paper-icon-button></paper-tab-->
<paper-tab tab="memories"><paper-icon-button icon="today"></paper-icon-button></paper-tab>
<paper-tab tab="albums"><paper-icon-button icon="folder"></paper-icon-button></paper-tab>
<paper-tab tab="thanksgiving"><paper-icon-button icon="maps:local-dining"></paper-icon-button></paper-tab>
<paper-tab tab="holiday"><paper-icon-button icon="redeem"></paper-icon-button></paper-tab>
<paper-tab hidden$="[[!user.maintainer]]" tab="duplicates"><paper-icon-button icon="compare-arrows"></paper-icon-button></paper-tab>
<paper-tab hidden$="[[!user.maintainer]]" tab="trash"><paper-icon-button icon="delete"></paper-icon-button></paper-tab>
</paper-tabs>
<iron-pages id="pages" attr-for-selected="id" selected="[[mode]]" fallback-selection="loading">
<div id="loading"></div>
<div id="holiday" class="flex layout vertical">
<div>Holidays</div>
<template is="dom-repeat" items="[[holidays]]">
<div tabindex="0" on-tap="loadHoliday">[[item]]</div>
</template>
</div>
<div id="time"><div>... time slider ...</div></div>
<div id="memories" class="flex layout vertical center">
<div class="memory-buttons layout self-stretch horizontal around-justified">
@ -386,7 +401,7 @@
<div tabindex="0" on-tap="loadPath">[[item.name]] /</div>
</template>
</div>
<div mode="thanksgiving">Thanksgiving!</div>
<div mode="holiday">[[holidayTitle]]</div>
<div mode="time">time</div>
<div mode="memories">Photos taken on <b on-tap="drawerToggle">[[memoryDate]]</b></div>
</iron-pages>
@ -551,6 +566,10 @@
date: {
type: String,
value: window.moment().format("YYYY-MM-DD")
},
holiday: {
type: String,
value: "Christmas"
}
},
@ -846,6 +865,12 @@
"iron-resize" : "onResize"
},
loadHoliday: function(event) {
this.holiday = event.model.item;
this.resetPhotos();
this._loadPhotos();
},
loadPath: function(event) {
this._pathLoad(event.model.item.path);
},
@ -1695,8 +1720,8 @@
path = "";
} else if (mode == "memories") {
path = "memories/" + (this.date.replace(this.year + "-", "") || "");
} else if (mode == "thanksgiving") {
path = "thanksgiving/";
} else if (mode == "holiday") {
path = "holiday/" + this.holiday;
}
}
var username = this.user ? this.user.username : "";
@ -1711,7 +1736,7 @@
if ((username != (this.user ? this.user.username : "")) ||
(mode != this.mode) ||
((mode == "albums") && (path != (this.path || ""))) ||
((mode == "thanksgiving") && (path != ("thanksgiving/"))) ||
((mode == "holiday") && (path != ("holiday/" + this.holiday))) ||
((mode == "memories") && (path != ("memories/" + (this.date.replace(this.year + "-", "") || ""))))) {
console.log("Skipping results for old query. Triggering re-fetch of photos for new path or mode.");
this._loadPhotos();
@ -1750,6 +1775,9 @@
this._loadPhotos(results.cursor, true, this.limit * 2);
}
if (this.mode == "holiday") {
this.holidayTitle = results.holiday;
}
}.bind(this, path));
},
@ -1903,6 +1931,30 @@
}
},
loadHolidays: function() {
window.fetch("api/v1/holidays", function(error, xhr) {
if (error) {
console.error(JSON.stringify(error, null, 2));
return;
}
var results;
try {
results = JSON.parse(xhr.responseText);
} catch (___) {
this.$.toast.text = "Unable to parse holidays.";
this.$.toast.setAttribute("error", true);
this.$.toast.updateStyles();
this.$.toast.show();
console.log(xhr.responseText);
return;
}
this.holiday = results.next;
this.holidays = results.holidays;
}.bind(this));
},
userChanged: function(user) {
if (!this.firstRequest) {
this.mode = "loading";
@ -1923,6 +1975,7 @@
if (!user.restriction) {
this.loginStatus = null;
this.mode = "memories";
this.loadHolidays();
this.setActions();
return;
}

View File

@ -25,6 +25,7 @@
"ldapauth-fork": "^4.0.2",
"mariasql": "^0.2.6",
"moment": "^2.22.2",
"moment-holiday": "^1.5.1",
"morgan": "^1.9.0",
"mustache": "^3.0.0",
"nodemailer": "^4.6.8",

View File

@ -263,6 +263,7 @@ app.use(basePath, express.static(picturesPath, { index: false }));
app.use(basePath + "api/v1/photos", require("./routes/photos"));
app.use(basePath + "api/v1/days", require("./routes/days"));
app.use(basePath + "api/v1/albums", require("./routes/albums"));
app.use(basePath + "api/v1/holidays", require("./routes/holidays"));
app.use(basePath + "api/v1/scan", require("./routes/scan")(scanner));
/* Declare the "catch all" index route last; the final route is a 404 dynamic router */

108
server/lib/pascha.js Normal file
View File

@ -0,0 +1,108 @@
//! moment-holiday.js locale configuration
//! locale : pascha Related Holidays
//! author : Kodie Grantham : https://github.com/kodie
//(function() {
// var moment = (typeof require !== 'undefined' && require !== null) && !require.amd ? require('moment') : this.moment;
function init(moment) {
// moment.holidays.pascha = {
moment.modifyHolidays.add({
"Lent": {
date: 'pascha-46|pascha-3'
},
/*
"Holy Monday": {
date: 'pascha-6',
keywords_y: ['great', 'monday']
},
"Holy Tuesday": {
date: 'pascha-5',
keywords_y: ['great', 'tuesday']
},
"Holy Wednesday": {
date: 'pascha-4',
keywords_y: ['great', 'wednesday']
},
"Holy Thursday": {
date: 'pascha-3',
keywords_y: ['great', 'thursday']
},
"Holy Friday": {
date: 'pascha-2',
keywords_y: ['great', 'friday']
},
"Holy Saturday": {
date: 'pascha-1',
keywords_y: ['holy', 'saturday']
},
*/
"Pascha Sunday": {
date: 'pascha',
keywords_y: ['pascha'],
keywords: ['sunday']
},
"Bright Week": {
date: 'pascha+1|pascha+6'
},
"Pentecost Sunday": {
date: 'pascha+49',
keywords_y: ['pentecost'],
keywords: ['sunday']
},
//};
});
/**
* Calculates Easter in the Gregorian/Western (Catholic and Protestant) calendar
* based on the algorithm by Oudin (1940) from http://www.tondering.dk/claus/cal/easter.php
* @returns {array} [int month, int day]
*/
var pascha = function(year) {
var f = Math.floor,
// Golden Number - 1
G = year % 19,
C = f(year / 100),
// related to Epact
H = (C-f(C / 4) - f((8 * C + 13)/25) + 19 * G + 15) % 30,
// number of days from 21 March to the Paschal full moon
I = H - f(H/28) * (1 - f(29/(H + 1)) * f((21-G)/11)),
// weekday for the Paschal full moon
J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7,
// number of days from 21 March to the Sunday on or before the Paschal full moon
L = I - J,
month = 3 + f((L + 40)/44),
day = L + 28 - 31 * f(month / 4);
return moment([year, (month - 1),day]);
}
moment.modifyHolidays.extendParser(function(m, date){
if (~date.indexOf('pascha')) {
var dates = date.split('|');
var ds = [];
for (var i = 0; i < dates.length; i++) {
if (dates[i].substring(0, 6) === 'pascha') {
var e = pascha(m.year());
if (dates[i].charAt(6) === '-') { e.subtract(dates[i].substring(7), 'days'); }
if (dates[i].charAt(6) === '+') { e.add(dates[i].substring(7), 'days'); }
if (dates.length === 1) { return e; }
ds.push(e.format('M/D'));
} else {
ds.push(dates[i]);
}
}
if (ds.length) { return ds.join('|'); }
}
});
console.log("Pascha initialized");
}
module.exports = init;
// if ((typeof module !== 'undefined' && module !== null ? module.exports : void 0) != null) { module.exports = moment; }
//}).call(this);

49
server/routes/holidays.js Normal file
View File

@ -0,0 +1,49 @@
"use strict";
const express = require("express"),
moment = require("moment-holiday");
require("../lib/pascha.js")(moment);
const router = express.Router();
/* Remove the western Easter dates, except for Easter itself */
[ 'Good Friday' ].forEach(function(holiday) {
moment.modifyHolidays.remove(holiday);
});
router.get("/", function(req, res/*, next*/) {
let holidays = [], skip = {};
moment("2000-01-01", "YYYY-MM-DD").holidaysBetween("2000-12-31").forEach(function(holiday) {
/* Dates with multiple holidays will return an array of items */
let names = holiday.isHoliday();
if (!Array.isArray(names)) {
names = [ names ];
}
names.forEach(function(name) {
if (name in skip) {
return;
}
/* If this holiday already exists, remove it from the holidays list
* as we only want single day events returned, and add to the 'skip'
* list */
let index = holidays.indexOf(name);
if (index != -1) {
holidays.splice(index, 1);
skip[name] = true;
} else {
holidays.push(name);
}
});
});
return res.status(200).send({
holidays: holidays,
next: moment().nextHoliday().isHoliday()
});
});
module.exports = router;

View File

@ -3,11 +3,13 @@
const express = require("express"),
fs = require("fs"),
config = require("config"),
moment = require("moment"),
moment = require("moment-holiday"),
crypto = require("crypto"),
util = require("util"),
Promise = require("bluebird");
require("../lib/pascha.js")(moment);
const execFile = util.promisify(require("child_process").execFile);
let photoDB;
@ -538,56 +540,40 @@ router.delete("/:id?", function(req, res/*, next*/) {
});
});
router.get("/thanksgiving", function(req, res/*, next*/) {
let thanksgiving = [
"1995-11-23",
"1996-11-28",
"1997-11-27",
"1998-11-26",
"1999-11-25",
"2000-11-23",
"2001-11-22",
"2002-11-28",
"2003-11-27",
"2004-11-25",
"2005-11-24",
"2006-11-23",
"2007-11-22",
"2008-11-27",
"2009-11-26",
"2010-11-25",
"2011-11-24",
"2012-11-22",
"2013-11-28",
"2014-11-27",
"2015-11-26",
"2016-11-24",
"2017-11-23",
"2018-11-22",
"2019-11-28",
"2020-11-26"
];
router.get("/holiday/:holiday", function(req, res/*, next*/) {
let startYear = 1990,
dayIsHoliday = "",
holidayName;
let dayIsThanksgiving = "";
thanksgiving.forEach(function(date) {
let comparison = "strftime('%Y-%m-%d',taken)='" + date + "'";
if (!dayIsThanksgiving) {
dayIsThanksgiving = comparison;
} else {
dayIsThanksgiving += " OR " + comparison;
let lookup = moment().holidays([req.params.holiday]);
if (!lookup) {
return res.status(404).send(req.params.holiday + " holiday not found.");
}
holidayName = Object.getOwnPropertyNames(lookup)[0];
for (let year = startYear; year <= moment().year(); year++) {
let holiday = moment(year + "-01-01", "YYYY-MM-DD").holiday(req.params.holiday);
if (!holiday) {
/* 'Leap Year' doesn't exist every year... */
continue;
}
});
let comparison = "strftime('%Y-%m-%d',taken)='" + holiday.format("YYYY-MM-DD") + "'"
if (!dayIsHoliday) {
dayIsHoliday = comparison;
} else {
dayIsHoliday += " OR " + comparison;
}
}
let query = "SELECT photos.*,albums.path AS path FROM photos " +
"INNER JOIN albums ON (albums.id=photos.albumId) " +
"WHERE (photos.duplicate=0 AND photos.deleted=0 AND photos.scanned NOT NULL AND (" + dayIsThanksgiving + ")) " +
"WHERE (photos.duplicate=0 AND photos.deleted=0 AND photos.scanned NOT NULL AND (" + dayIsHoliday + ")) " +
"ORDER BY strftime('%Y-%m-%d', taken) DESC,id DESC";
return photoDB.sequelize.query(query, {
type: photoDB.Sequelize.QueryTypes.SELECT
}).then(function(photos) {
console.log(query);
console.log(JSON.stringify(photos));
photos.forEach(function(photo) {
for (var key in photo) {
if (photo[key] instanceof Date) {
@ -597,6 +583,7 @@ router.get("/thanksgiving", function(req, res/*, next*/) {
});
return res.status(200).json({
holiday: holidayName,
items: photos
});