import { Controller, view, Injectable, SecurityContext, Inject, Collection, Config, Routing, file, Application, make, Valid, Logging, api, Session, } from '@extollo/lib' import {WorkItem} from '../../models/WorkItem.model' import {FeedPost} from '../../models/FeedPost.model' import {ContactForm} from '../../types/ContactForm.type' import {ContactSubmission} from '../../models/ContactSubmission.model' import {Gotify} from 'gotify' import {ColorPalette} from '../../configs/app.config' @Injectable() export class Home extends Controller { @Inject() protected readonly security!: SecurityContext @Inject() protected readonly config!: Config @Inject() protected readonly routing!: Routing @Inject() protected readonly gotify!: Gotify @Inject() protected readonly logging!: Logging @Inject() protected readonly session!: Session public async welcome(feedPosts: Collection) { const workItems = await this.getWorkItems() const workItemYears = workItems.map(item => item.startDate.getFullYear()).unique() const workItemVisibleYears = workItems.filter(item => !item.endDate) .map(item => item.startDate.getFullYear()) .unique() return view('welcome', { ...this.getThemeCSS(), feedPosts: feedPosts.toArray(), workItemGroups: workItems.groupBy(item => item.startDate.getFullYear()), workItemYears: workItemYears.toArray(), workItemHiddenYears: workItemYears.diff(workItemVisibleYears) }) } public technical() { const isOptOut = this.request.cookies.has(this.config.get('app.analytics.optOutCookie')) return view('technical', { isOptOut, ...this.getThemeCSS(), }) } public optOutPrompt() { return view('message', { title: 'Analytics Opt-Out', message: 'This will set a cookie to disable analytics recording in your browser on all *.garrettmills.dev sites. Continue?', buttonAction: this.routing.getNamedPath('opt-out').toRemote, buttonMethod: 'post', ...this.getThemeCSS(), }) } public optOut() { this.request.cookies.set( this.config.get('app.analytics.optOutCookie'), true, { expires: new Date(Date.now() + (1000 * 60 * 60 * 24 * 365 * 100)), secure: true, httpOnly: true, path: '/', }, ) return view('message', { title: 'Analytics Opt-Out', message: 'You have been opted-out of analytics recording.', buttonAction: this.routing.getNamedPath('home').toRemote, ...this.getThemeCSS(), }) } protected async getWorkItems(): Promise> { const query = WorkItem.query() .orderByDescending('start_date') if ( !this.security.hasUser() ) { query.where('visible', '=', true) } return query.get().collect() } favicon() { return file( Application.getApplication() .appPath('resources', 'assets', 'favicon', 'favicon.ico') ) } humans() { return Application.getApplication() .appPath('resources', 'assets', 'humans.txt') .read() } async contact(data: ContactForm) { await this.sendContact(data) return view('message', { title: 'Message Sent', message: 'Your message has been sent. Thanks! I\'ll be in touch soon.', buttonAction: this.routing.getNamedPath('home').toRemote, ...this.getThemeCSS(), }) } async contactApi(data: ContactForm) { await this.sendContact(data) return api.one({}) } protected async sendContact(data: ContactForm) { const submission = make(ContactSubmission) submission.name = data.name submission.email = data.email submission.message = data.message await submission.save() this.gotify.send({ app: this.config.get('gotify.app'), title: `Contact form submission from ${data.name}`, priority: 5, message: [ `From: ${data.name}`, `E-mail: ${data.email}`, 'Message:', data.message, ].join('\n'), }).then(x => this.logging.debug(x)) .catch(e => this.logging.error(e)) } public getThemeCSS(): any { const themes = this.config.get('app.colors') as Record const themeKeys = Object.keys(themes) const themeName = this.session.get('theme.name') // const themeName = this.request.safe('theme').or(themeKeys[Math.floor(Math.random()*themeKeys.length)]).in(themeKeys) const theme = themes[themeName] const themeCSS = ` :root { --c-background: ${theme.background}; --c-background-offset: ${theme.backgroundOffset}; --c-background-offset-2: ${theme.backgroundOffset2}; --c-hero: ${theme.hero}; --c-font: ${theme.font}; --c-font-muted: ${theme.fontMuted}; --c-box: ${theme.box}; --c-link: ${theme.link}; --c-noise-size: ${theme.noiseSize}; --c-line-1: ${theme.line1}; --c-line-2: ${theme.line2}; --c-line-3: ${theme.line3}; } ` return { themeName, themeCSS, themeDisplayName: theme.displayName, themeKeys, themeRecord: theme, } } }