diff --git a/Dockerfile b/Dockerfile index 2173d04..59f865a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,10 +7,10 @@ RUN npm install -g pnpm RUN pnpm install --frozen-lockfile FROM node:lts-alpine AS builder -ARG APP_ENV +# ARG APP_ENV WORKDIR /app COPY . . -COPY .env.$APP_ENV .env +COPY .env .env COPY --from=deps /app/node_modules ./node_modules RUN npm run build @@ -19,7 +19,7 @@ WORKDIR /usr/app ARG APP_ENV COPY --from=builder /app/build ./build COPY package.json ./ -COPY .env.$APP_ENV .env +COPY .env .env RUN npm install -g pnpm RUN pnpm install --prod USER node diff --git a/README.md b/README.md index 5f46f78..68a36a3 100644 --- a/README.md +++ b/README.md @@ -7,19 +7,21 @@ Ever felt like you need to have a privacy-respecting alternative for everything? Next pro comes in the form of customization. By fetching the raw data and ~~formatting it~~ trying to format it into a reasonable JSON object, you are not limited by some embed image returned by a server. Let your creativity flow into your theme, which can be made by simply throwing some HTML and CSS together. Or if you're lazy, just use some of the pre-made ones (unless you use the ones I made, they are ugly). ## Configuration -TODO +Refer to [configuration.md](./docs/configuration.md). ## Roadmap - [X] Easy theme switching -- [] Actual caching!!!!! -- [] ListenBrainz current/last listening -- [] Contact form that sends stuff somewhere -- [] Shoutbox -- [] Discord online/offline??? (idk probably needs a bot) -- [] Fetch latest Mastodon post -- [] Follower counts for different sites +- [ ] Actual caching!!!!! +- [ ] ListenBrainz current/last listening +- [ ] Contact form that sends stuff somewhere +- [ ] Shoutbox +- [ ] Discord online/offline??? (idk probably needs a bot) +- [X] Fetch latest Mastodon post +- [ ] Follower counts for different sites - [X] Dynamically add custom pages -- [] Mini CMS blog +- [ ] Mini CMS blog +- [ ] Gallery +- [ ] Comments ## License ``` diff --git a/config.json b/config.json index 36e6e57..78264b2 100644 --- a/config.json +++ b/config.json @@ -15,6 +15,7 @@ "enabled":true, "method":"friendly", "secretKey":"", - "clientKey":"" + "clientKey":"", + "url":"" } } \ No newline at end of file diff --git a/package.json b/package.json index c4b7822..3fd291b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "fastify-typescript-starter", - "version": "1.5.0", - "description": "Node.js boilerplate using fastify & TypeScript", + "name": "egoport", + "version": "0.1.0", + "description": "Your personal portfolio, serving stuff while respecting user privacy", "type": "module", "scripts": { "lint": "eslint .", @@ -15,10 +15,6 @@ "test": "vitest", "test:watch": "vitest -w" }, - "repository": { - "type": "git", - "url": "git+https://github.com/yonathan06/fastify-typescript-starter.git" - }, "engines": { "node": ">=16.0.0" }, @@ -27,12 +23,12 @@ "fastify", "typescript" ], - "author": "Yonatan Bendahan", - "license": "MIT", + "author": "Matyáš Caras", + "license": "AGPL-3.0-only", "bugs": { - "url": "https://github.com/yonathan06/fastify-typescript-starter/issues" + "url": "https://git.mnau.xyz/hernik/egoport/issues" }, - "homepage": "https://github.com/yonathan06/fastify-typescript-starter#readme", + "homepage": "https://git.mnau.xyz/hernik/egoport#readme", "dependencies": { "@fastify/static": "^6.12.0", "@fastify/view": "^8.2.0", @@ -44,6 +40,7 @@ "env-schema": "^5.2.1", "fastify": "^4.24.3", "fastify-plugin": "^3.0.1", + "node-cache": "^5.1.2", "ts-json-validator": "^0.7.1" }, "devDependencies": { diff --git a/src/api/mastodon.ts b/src/api/mastodon.ts index 5d44435..5771d45 100644 --- a/src/api/mastodon.ts +++ b/src/api/mastodon.ts @@ -11,7 +11,7 @@ async function findMastodonUser(username: string, host: string): Promise console.error(res.data); return ''; } - return JSON.parse(res.data)['accounts'][0]['id']; + return res.data['accounts'][0]['id']; } interface MastodonPost { @@ -21,6 +21,8 @@ interface MastodonPost { reblogs: number; replies: number; inReplyTo?: string; + mediaUrls: string[]; + user: string; } async function getLatestMastodonPost(id: string, host: string): Promise { @@ -34,11 +36,17 @@ async function getLatestMastodonPost(id: string, host: string): Promise { + if (media['url'] != null) { + mediaUrl.push(media['url'] as string); + } + }); return { url: data['url'], content: decodeURI(data['content']), @@ -46,7 +54,9 @@ async function getLatestMastodonPost(id: string, host: string): Promise { server.get('/', {}, async function (req, res) { @@ -19,7 +20,21 @@ const routes: FastifyPluginAsync = async (server) => { console.error('Check your config.json file!'); process.exit(1); } - return res.view('index.ejs',{title:userConfig.title,subtitle:userConfig.subtitle}); + try { + let mastodon = undefined; + if(userConfig.mastodon != null && userConfig.mastodon.host != undefined && userConfig.mastodon.username != undefined){ + let user = userConfig.mastodon.username + if(/\w/gm.test(user)){ + // TODO: save ID to config + user = await findMastodonUser(userConfig.mastodon.username,userConfig.mastodon.host); + } + mastodon = await getLatestMastodonPost(user,userConfig.mastodon.host) + } + return res.view('index.ejs',{title:userConfig.title,subtitle:userConfig.subtitle,mastodon}); + } catch (error) { + console.error("Error while rendering index! Got following error:") + console.error(error) + } }); }; diff --git a/src/server.ts b/src/server.ts index 1896ee0..a1907b6 100644 --- a/src/server.ts +++ b/src/server.ts @@ -15,6 +15,7 @@ const parser = new TsjsonParser( title: 'EGOport Configuration', description: 'Configuration for the EGOport program', type: 'object', + additionalProperties:S(false), properties: { theme: S({ description: "The name of the theme matching a name of a folder inside 'themes'", @@ -43,6 +44,7 @@ const parser = new TsjsonParser( type: 'object', description: 'Contains configuration for the Mastodon integration', default: {}, + additionalProperties:S(false), properties: { host: S({ type: 'string', @@ -69,13 +71,14 @@ const parser = new TsjsonParser( }), captcha: S({ type:"object", + additionalProperties:S(false), properties:{ enabled: S({ type:"boolean", description:"Whether captcha should be enabled on shoutbox/contact form", default:true }), - host: S({ + method: S({ type:"string", description:"Who will provide the CAPTCHA service", enum: ["friendly","mosparo"], diff --git a/themes/default/index.ejs b/themes/default/index.ejs index 789bf40..edacecc 100644 --- a/themes/default/index.ejs +++ b/themes/default/index.ejs @@ -18,6 +18,10 @@ <% if (subtitle) { %>

<%= subtitle %>

<% } %> +

Latest Mastodon post:

+ <% if (mastodon){ %> + <%- include('widgets/mastodon',{mastodon:mastodon}) %> + <% } %>