Browse Source

the last few things.

master
Gisle Aune 4 years ago
parent
commit
6aef0412e8
  1. 18
      marko/page/data/components/changes-page/component.js
  2. 4
      marko/page/data/components/changes-page/index.marko
  3. 17
      marko/page/data/components/changes-page/style.less
  4. 86
      marko/page/logs-content/components/log-suggestions/component.js
  5. 54
      marko/page/logs-content/components/log-suggestions/index.marko
  6. 7
      marko/page/logs/components/page/component.js
  7. 4
      marko/page/logs/components/page/index.marko
  8. 5
      marko/page/logs/components/page/style.less
  9. 3
      middleware/passport.js
  10. 2
      middleware/session.js
  11. 16
      routes/auth.js
  12. 4
      routes/data/changes.js
  13. 22
      rpdata/api/Log.js

18
marko/page/data/components/changes-page/component.js

@ -1,11 +1,27 @@
const { changesApi } = require("../../../../../rpdata/api/Change")
module.exports = class { module.exports = class {
onCreate(input) { onCreate(input) {
this.state = { this.state = {
characters: input.characters,
changes: input.changes,
shownAll: false,
modal: null, modal: null,
} }
} }
clearLimit(e) {
// Disable mobile URL fallback.
if (e && e.preventDefault) {
e.preventDefault()
}
changesApi.list({limit: 0}).then(changes => {
this.state.changes = changes
this.state.shownAll = true
})
}
open(modal) { open(modal) {
this.state.modal = modal this.state.modal = modal
} }

4
marko/page/data/components/changes-page/index.marko

@ -3,10 +3,12 @@
<div class="changes-page"> <div class="changes-page">
<h1 class="color-primary">Changes</h1> <h1 class="color-primary">Changes</h1>
<p>All changes to <em>listed</em> resources is stored for 90 days for transparency reasons. The current state of an object after each change exists, but is only available through the GraphQL API at this time.</p> <p>All changes to <em>listed</em> resources is stored for 90 days for transparency reasons. The current state of an object after each change exists, but is only available through the GraphQL API at this time.</p>
<for (change in input.changes)>
<for (change in state.changes)>
<change data=change /> <change data=change />
</for> </for>
<a if(!state.shownAll) href="/data/changes?limit=0" class="show-more-button" on-click("clearLimit")>Show All</a>
</div> </div>
</main> </main>
<add-character-modal enabled=(state.modal === "character.add") user=input.user on-added("characterAdded") on-close("close") /> <add-character-modal enabled=(state.modal === "character.add") user=input.user on-added("characterAdded") on-close("close") />
<add-channel-modal enabled=(state.modal === "channel.add") user=input.user on-close("close") /> <add-channel-modal enabled=(state.modal === "channel.add") user=input.user on-close("close") />
<add-file-modal enabled=(state.modal === "file.add") user=input.user on-close("close") />

17
marko/page/data/components/changes-page/style.less

@ -33,4 +33,21 @@
opacity: 1; opacity: 1;
} }
} }
.show-more-button {
margin: 1em 0;
padding: 0.5em 2em;
font-size: 2em;
text-align: center;
user-select: none;
display: block;
color: #DA1;
}
.show-more-button:hover {
cursor: pointer;
text-decoration: underline;
}
} }

86
marko/page/logs-content/components/log-suggestions/component.js

@ -1,96 +1,10 @@
const {logHeaderApi} = require("../../../../../rpdata/api/LogHeader")
module.exports = class { module.exports = class {
onCreate(input) { onCreate(input) {
this.state = { this.state = {
id: input.log.id, id: input.log.id,
channelName: input.log.channelName, channelName: input.log.channelName,
eventName: input.log.eventName, eventName: input.log.eventName,
nexts: [],
prevs: [],
loaded: false,
error: null, error: null,
} }
} }
onMount() {
this.timeout = setTimeout(() => {
logHeaderApi.list().then(logs => {
const index = logs.findIndex(l => l.id === this.state.id);
if (index === -1) {
return Promise.reject("This log not found in list.")
}
const log = logs[index]
const characterIds = log.characters.map(c => c.id);
const nexts = []
const prevs = []
let foundGroups = {}
let foundChannel = false
for (let i = index - 1; i >= 0; --i) {
const log2 = logs[i]
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
const hasChannel = (log.channelName === log2.channelName)
const characters = log2.findCharacters(...characterIds)
const characterIdsKey = characters.map(c => c.id).sort().join(",")
const suggestion = {log: log2, characters, hasEvent, hasChannel}
if (hasChannel && !foundChannel) {
foundChannel = true
foundGroups[characterIdsKey] = true
nexts.push(suggestion)
} else if (hasEvent) {
foundGroups[characterIdsKey] = true
nexts.push(suggestion)
} else if (nexts.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
foundGroups[characterIdsKey] = true
nexts.push(suggestion)
}
}
foundGroups = {}
foundChannel = false
for (let i = index + 1; i < logs.length; ++i) {
const log2 = logs[i]
const hasEvent = (log.eventName ? log.eventName === log2.eventName : false)
const hasChannel = (log.channelName === log2.channelName)
const characters = log2.findCharacters(...characterIds)
const characterIdsKey = characters.map(c => c.id).sort().join(",")
const suggestion = {log: log2, characters, hasEvent, hasChannel}
if (hasChannel && !foundChannel) {
foundChannel = true
foundGroups[characterIdsKey] = true
prevs.push(suggestion)
} else if (hasEvent) {
foundGroups[characterIdsKey] = true
prevs.push(suggestion)
} else if (prevs.length < 8 && !hasEvent && characters.length > 1 && !foundGroups[characterIdsKey]) {
foundGroups[characterIdsKey] = true
prevs.push(suggestion)
}
}
this.state.nexts = nexts;
this.state.prevs = prevs;
this.state.loaded = true;
}).catch(err => {
console.warn("Suggestions load error:", err)
this.suggestionsError = "Failed to load suggestions: " + err.toString()
})
}, 1000)
}
onUnmount() {
clearTimeout(this.timeout)
}
} }

54
marko/page/logs-content/components/log-suggestions/index.marko

@ -1,41 +1,33 @@
import moment from "moment" import moment from "moment"
<div class="log-suggestions"> <div class="log-suggestions">
<if (state.loaded && state.error == null)>
<if (state.nexts.length > 0 || state.prevs.length > 0)>
<if (state.nexts.length > 0)>
<h2 class="color-primary">Next Logs</h2>
<div for(s in state.nexts) class="suggestion color-primary">
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
<div class="suggestion-tags">
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
</div>
<if (input.log.nextLogs.length > 0 || input.log.prevLogs.length > 0)>
<if (input.log.nextLogs.length > 0)>
<h2 class="color-primary">Next Logs</h2>
<div for(s in input.log.nextLogs) class="suggestion color-primary">
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.title || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
<div class="suggestion-tags">
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${input.log.eventName}</div>
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
</div> </div>
</if>
<if (state.prevs.length > 0)>
<h2 class="color-primary">Previous Logs</h2>
<div for(s in state.prevs) class="suggestion color-primary">
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.name || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
<div class="suggestion-tags">
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${s.log.eventName}</div>
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
</div>
</div>
</if>
<if (input.log.prevLogs.length > 0)>
<h2 class="color-primary">Previous Logs</h2>
<div for(s in input.log.prevLogs) class="suggestion color-primary">
<div class="suggestion-header color-primary"><a href=`/logs/${s.log.id}`>${s.log.title || `${s.log.channelName} - ${moment(s.log.date).format("MMMM D, YYYY")}`}</a></div>
<div for(paragraph in (s.log.description||"").split("\n").filter(p => p)) class="suggestion-description color-text">${paragraph}</div>
<div class="suggestion-tags">
<div if(s.hasEvent) class="suggestion-tag color-tag-event">${input.log.eventName}</div>
<div if(s.hasChannel) class="suggestion-tag color-tag-location">${s.log.channelName}</div>
<div for(c in s.characters) class="suggestion-tag color-tag-character">${c.name}</div>
</div> </div>
</if>
</div>
</if> </if>
<else>
<div class="empty color-menu">(No suggestions)</div>
</else>
</if> </if>
<else-if(state.error != null)>
<div class="error color-danger">{state.error}</div>
</else-if>
<else> <else>
<div class="loading color-menu">Loading suggestions...</div>
<div class="empty color-menu">(No suggestions)</div>
</else> </else>
</div> </div>

7
marko/page/logs/components/page/component.js

@ -79,9 +79,14 @@ module.exports = class {
} }
} }
clearLimit() {
clearLimit(e) {
this.state.filter = Object.assign({}, this.state.filter, {limit: 0}) this.state.filter = Object.assign({}, this.state.filter, {limit: 0})
// Disable mobile URL fallback.
if (e && e.preventDefault) {
e.preventDefault()
}
this.refresh() this.refresh()
this.updateQuery(this.state.filter) this.updateQuery(this.state.filter)
} }

4
marko/page/logs/components/page/index.marko

@ -4,9 +4,9 @@
<main class="logs-page with-right"> <main class="logs-page with-right">
<logs-table logs=state.logs on-addfilter("addFilter") /> <logs-table logs=state.logs on-addfilter("addFilter") />
<if(state.filter.limit > 0)> <if(state.filter.limit > 0)>
<div class="show-more-button" on-click("clearLimit")>
<a href="/logs?limit=0" class="show-more-button" on-click("clearLimit")>
<span>Show All</span> <span>Show All</span>
</div>
</a>
</if> </if>
</main> </main>
<add-log-modal enabled=(state.modal === "log.add") on-close("close") /> <add-log-modal enabled=(state.modal === "log.add") on-close("close") />

5
marko/page/logs/components/page/style.less

@ -1,15 +1,16 @@
main.logs-page { main.logs-page {
div.show-more-button {
.show-more-button {
margin: 1em 0; margin: 1em 0;
padding: 0.5em 2em; padding: 0.5em 2em;
font-size: 2em; font-size: 2em;
text-align: center; text-align: center;
user-select: none; user-select: none;
display: block;
color: #DA1; color: #DA1;
} }
div.show-more-button:hover {
.show-more-button:hover {
cursor: pointer; cursor: pointer;
text-decoration: underline; text-decoration: underline;

3
middleware/passport.js

@ -7,7 +7,8 @@ const strategy = new Auth0Strategy({
domain: config.auth0.domain, domain: config.auth0.domain,
clientID: config.auth0.clientId, clientID: config.auth0.clientId,
clientSecret: config.auth0.secret, // Replace this with the client secret for your app clientSecret: config.auth0.secret, // Replace this with the client secret for your app
callbackURL: config.root + "/auth/callback"
callbackURL: config.root + "/auth/callback",
state: true,
}, (accessToken, refreshToken, extraParams, profile, done) => { }, (accessToken, refreshToken, extraParams, profile, done) => {
// accessToken is the token to call Auth0 API (not needed in the most cases) // accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token // extraParams.id_token has the JSON Web Token

2
middleware/session.js

@ -6,7 +6,7 @@ module.exports = session({
secret: config.session.secret, secret: config.session.secret,
store: new RedisStore(config.redis), store: new RedisStore(config.redis),
cookie: { cookie: {
secure: config.session.secure
secure: config.session.secure,
}, },
resave: false, resave: false,
saveUninitialized: true, saveUninitialized: true,

16
routes/auth.js

@ -17,12 +17,16 @@ router.get("/login", saveReferer, passport.authenticate("auth0", {scope: "openid
res.redirect("/") res.redirect("/")
}) })
router.get("/callback", passport.authenticate("auth0"), (req, res) => {
if (req.user == null) {
throw new Error("user null");
}
res.redirect(req.session.loginReferrer || "/");
router.get("/callback", function (req, res, next) {
passport.authenticate("auth0", function (err, user, info) {
if (err) { return next(err) }
if (!user) { console.log(err, user, info); return res.redirect("/auth/login") }
req.logIn(user, function (err) {
if (err) { return next(err) }
res.redirect(req.session.loginReferrer || "/");
})
})(req, res, next);
}) })
router.get("/user", (req, res) => { router.get("/user", (req, res) => {

4
routes/data/changes.js

@ -6,8 +6,10 @@ const {changesApi} = require("../../rpdata/api/Change")
const changesTemplate = require("../../marko/page/data/changes.marko") const changesTemplate = require("../../marko/page/data/changes.marko")
router.get("/", async(req, res) => { router.get("/", async(req, res) => {
const limit = parseInt(req.query.limit) || 100
res.markoAsync(changesTemplate, { res.markoAsync(changesTemplate, {
changes: changesApi.list({limit: 1000}),
changes: changesApi.list({limit}),
selected: {changes: true}, selected: {changes: true},
}) })
}) })

22
rpdata/api/Log.js

@ -31,7 +31,11 @@ class Log {
} }
static fromData(data) { static fromData(data) {
return new Log(data.id, data.shortId, data.date, data.title, data.eventName, data.description, data.open, data.channel, data.characters, data.posts)
return new Log(
data.id, data.shortId, data.date,
data.title, data.eventName, data.description,
data.open, data.channel, data.characters, data.posts
)
} }
} }
@ -70,10 +74,22 @@ class LogAPI {
nick nick
text text
} }
nextLogs {
log {id title date channelName}
hasEvent
hasChannel
characters {name}
}
prevLogs {
log {id title date channelName}
hasEvent
hasChannel
characters {name}
}
} }
} }
`, {id}).then(({log}) => { `, {id}).then(({log}) => {
return Log.fromData(log)
return log
}) })
} }
@ -219,7 +235,7 @@ class LogAPI {
subscribeChanges(logId) { subscribeChanges(logId) {
return new Subscription(` return new Subscription(`
subscription Changes($keys: [ChangeKeyInput!]!) { subscription Changes($keys: [ChangeKeyInput!]!) {
changes(keys: $keys) {
changes(filter: {keys: $keys}) {
id id
model model
op op

Loading…
Cancel
Save