Added holiday picker
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
63e44c5ad3
commit
182606db20
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
108
server/lib/pascha.js
Normal 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
49
server/routes/holidays.js
Normal 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;
|
@ -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
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user