This is way too much time to spend on linters
This commit is contained in:
parent
69ebed5c7e
commit
0c880a7b4e
23
.eslintrc.js
23
.eslintrc.js
@ -5,7 +5,10 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
"plugin:react/recommended",
|
"plugin:react/recommended",
|
||||||
"standard"
|
"standard",
|
||||||
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint",
|
||||||
|
"prettier/react"
|
||||||
],
|
],
|
||||||
parser: "@typescript-eslint/parser",
|
parser: "@typescript-eslint/parser",
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
@ -25,25 +28,21 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"space-before-function-paren": ["error", {
|
"no-unused-vars": ["error", {
|
||||||
anonymous: "always",
|
"vars": "all",
|
||||||
named: "never",
|
"args": "after-used"
|
||||||
asyncArrow: "always"
|
|
||||||
}],
|
}],
|
||||||
"quote-props": ["error", "consistent"],
|
|
||||||
"quotes": ["error", "double"],
|
|
||||||
"sort-imports": ["error", {
|
|
||||||
"ignoreCase": true,
|
|
||||||
"allowSeparatedGroups": true
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ["*.ts", "*.tsx"],
|
files: ["*.ts", "*.tsx"],
|
||||||
rules: {
|
rules: {
|
||||||
|
"no-undef": "off",
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars-experimental": "error"
|
"@typescript-eslint/no-unused-vars-experimental": ["error", {
|
||||||
|
"ignoreArgsIfArgsAfterAreUsed": true
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
dist
|
||||||
|
node_packages
|
3
.prettierrc.json
Normal file
3
.prettierrc.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"quoteProps": "consistent"
|
||||||
|
}
|
1640
package-lock.json
generated
1640
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@ -56,10 +56,23 @@
|
|||||||
"@types/react-router-dom": "^5.1.3",
|
"@types/react-router-dom": "^5.1.3",
|
||||||
"@types/webpack-dev-middleware": "^2.0.4",
|
"@types/webpack-dev-middleware": "^2.0.4",
|
||||||
"@types/yargs": "^13.0.8",
|
"@types/yargs": "^13.0.8",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^3.9.1",
|
||||||
|
"@typescript-eslint/parser": "^3.9.1",
|
||||||
"css-loader": "^3.4.2",
|
"css-loader": "^3.4.2",
|
||||||
|
"eslint": "^7.7.0",
|
||||||
|
"eslint-config-prettier": "^6.11.0",
|
||||||
|
"eslint-config-standard": "^14.1.1",
|
||||||
|
"eslint-plugin-import": "^2.22.0",
|
||||||
|
"eslint-plugin-node": "^11.1.0",
|
||||||
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
"eslint-plugin-react": "^7.20.6",
|
||||||
|
"eslint-plugin-standard": "^4.0.1",
|
||||||
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"object-hash": "^2.0.3",
|
"object-hash": "^2.0.3",
|
||||||
"pg-monitor": "^1.3.1",
|
"pg-monitor": "^1.3.1",
|
||||||
"pino-pretty": "^3.6.1",
|
"pino-pretty": "^3.6.1",
|
||||||
|
"prettier": "2.0.5",
|
||||||
|
"prettier-plugin-organize-imports": "^1.1.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
@ -72,8 +85,6 @@
|
|||||||
"ts-node": "^8.8.1",
|
"ts-node": "^8.8.1",
|
||||||
"ts-node-dev": "^1.0.0-pre.44",
|
"ts-node-dev": "^1.0.0-pre.44",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tslint": "^5.20.1",
|
|
||||||
"tslint-config-prettier": "^1.18.0",
|
|
||||||
"typescript": "^4.0.2",
|
"typescript": "^4.0.2",
|
||||||
"webpack": "^4.44.1",
|
"webpack": "^4.44.1",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
|
@ -18,7 +18,7 @@ export const getTasks = async (
|
|||||||
throw new APIError("Invalid response from server.");
|
throw new APIError("Invalid response from server.");
|
||||||
}
|
}
|
||||||
const count: number = json.count;
|
const count: number = json.count;
|
||||||
const items: Task[] = (json.tasks as any[]).map(t => {
|
const items: Task[] = (json.tasks as any[]).map((t) => {
|
||||||
if (
|
if (
|
||||||
typeof t !== "object" ||
|
typeof t !== "object" ||
|
||||||
!Number.isSafeInteger(t.id) ||
|
!Number.isSafeInteger(t.id) ||
|
||||||
@ -30,7 +30,7 @@ export const getTasks = async (
|
|||||||
return {
|
return {
|
||||||
id: t.id,
|
id: t.id,
|
||||||
name: t.name,
|
name: t.name,
|
||||||
schedule: { type: "Plain" }
|
schedule: { type: "Plain" },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,24 +2,33 @@ import * as React from "react";
|
|||||||
import { BrowserRouter as Router, Link, Route, Switch } from "react-router-dom";
|
import { BrowserRouter as Router, Link, Route, Switch } from "react-router-dom";
|
||||||
import TaskList from "./TaskList";
|
import TaskList from "./TaskList";
|
||||||
|
|
||||||
export default () => <Router>
|
function App() {
|
||||||
|
return (
|
||||||
|
<Router>
|
||||||
<div>
|
<div>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/auth">Login</a></li>
|
<li>
|
||||||
<li><Link to="/about">About</Link></li>
|
<a href="/auth">Login</a>
|
||||||
<li><Link to="/">Tasks</Link></li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/about">About</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link to="/">Tasks</Link>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/about">
|
<Route path="/about">About things, yay!</Route>
|
||||||
About things, yay!
|
|
||||||
</Route>
|
|
||||||
<Route path="/">
|
<Route path="/">
|
||||||
<TaskList />
|
<TaskList />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
||||||
|
@ -4,7 +4,7 @@ import { Task, TaskScheduleType } from "@kredens/frontend/store/tasks/types";
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
export default () => {
|
function TaskList() {
|
||||||
const [taskName, setTaskName] = useState("");
|
const [taskName, setTaskName] = useState("");
|
||||||
const tasks = useSelector<AppState, { [key: string]: Task }>(state => state.tasks.items);
|
const tasks = useSelector<AppState, { [key: string]: Task }>(state => state.tasks.items);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -37,3 +37,5 @@ export default () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default TaskList
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tslint.json",
|
|
||||||
"rules": {
|
|
||||||
"no-implicit-dependencies": [
|
|
||||||
true,
|
|
||||||
"dev",
|
|
||||||
["@kredens/frontend"]
|
|
||||||
],
|
|
||||||
"no-submodule-imports": [
|
|
||||||
true,
|
|
||||||
"@kredens/frontend",
|
|
||||||
"redux-saga/effects"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,7 +24,7 @@ export const getUser = async (req: express.Request) =>
|
|||||||
|
|
||||||
export const authMiddleware: () => express.Handler = () => async (
|
export const authMiddleware: () => express.Handler = () => async (
|
||||||
req,
|
req,
|
||||||
res,
|
_res,
|
||||||
next
|
next
|
||||||
) => {
|
) => {
|
||||||
if (req.session.userID) {
|
if (req.session.userID) {
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
decodeBase64,
|
decodeBase64,
|
||||||
decodeUTF8,
|
decodeUTF8,
|
||||||
encodeBase64,
|
encodeBase64,
|
||||||
encodeUTF8
|
encodeUTF8,
|
||||||
} from "tweetnacl-util";
|
} from "tweetnacl-util";
|
||||||
|
|
||||||
const secret = decodeBase64(process.env.SECRET);
|
const secret = decodeBase64(process.env.SECRET);
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
MigrationRepository,
|
MigrationRepository,
|
||||||
SessionRepository,
|
SessionRepository,
|
||||||
TaskRepository,
|
TaskRepository,
|
||||||
UserRepository
|
UserRepository,
|
||||||
} from "@kredens/server/db/repos";
|
} from "@kredens/server/db/repos";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import pg from "pg";
|
import pg from "pg";
|
||||||
@ -31,19 +31,19 @@ types.setTypeParser(types.builtins.TIMESTAMP, DateTime.fromSQL);
|
|||||||
type ExtendedProtocol = IDatabase<Extensions> & Extensions;
|
type ExtendedProtocol = IDatabase<Extensions> & Extensions;
|
||||||
|
|
||||||
const initOptions: IInitOptions<Extensions> = {
|
const initOptions: IInitOptions<Extensions> = {
|
||||||
extend(obj: ExtendedProtocol, dc: any) {
|
extend(obj: ExtendedProtocol) {
|
||||||
obj.migrations = new MigrationRepository(obj, pgp);
|
obj.migrations = new MigrationRepository(obj, pgp);
|
||||||
obj.tasks = new TaskRepository(obj, pgp);
|
obj.tasks = new TaskRepository(obj, pgp);
|
||||||
obj.users = new UserRepository(obj, pgp);
|
obj.users = new UserRepository(obj, pgp);
|
||||||
obj.sessions = new SessionRepository(obj, pgp);
|
obj.sessions = new SessionRepository(obj, pgp);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const pgp: pgPromise.IMain = pgPromise(initOptions);
|
const pgp: pgPromise.IMain = pgPromise(initOptions);
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== "production") {
|
if (process.env.NODE_ENV !== "production") {
|
||||||
// tslint:disable-next-line:no-implicit-dependencies
|
// tslint:disable-next-line:no-implicit-dependencies
|
||||||
import("pg-monitor").then(monitor => monitor.attach(initOptions));
|
import("pg-monitor").then((monitor) => monitor.attach(initOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
const db: ExtendedProtocol = pgp(process.env.DATABASE_URL);
|
const db: ExtendedProtocol = pgp(process.env.DATABASE_URL);
|
||||||
|
@ -24,7 +24,7 @@ export class LockError extends Error {}
|
|||||||
export class MigrationRepository {
|
export class MigrationRepository {
|
||||||
private db: IDatabase<any>;
|
private db: IDatabase<any>;
|
||||||
|
|
||||||
constructor(db: IDatabase<any>, pgp: IMain) {
|
constructor(db: IDatabase<any>, _pgp: IMain) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,15 +45,15 @@ export class MigrationRepository {
|
|||||||
|
|
||||||
public async apply() {
|
public async apply() {
|
||||||
await this.lock();
|
await this.lock();
|
||||||
const applied = (await this.applied()).map(m => m.name);
|
const applied = (await this.applied()).map((m) => m.name);
|
||||||
const toApply = sql.patches.filter(
|
const toApply = sql.patches.filter(
|
||||||
p => p.up.isSome() && !applied.find(o => o === p.name)
|
(p) => p.up.isSome() && !applied.find((o) => o === p.name)
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const patch of toApply) {
|
for (const patch of toApply) {
|
||||||
logger.info("Applying migration", { name: patch.name });
|
logger.info("Applying migration", { name: patch.name });
|
||||||
await patch.up
|
await patch.up
|
||||||
.map(async qf => {
|
.map(async (qf) => {
|
||||||
await this.db.none(qf);
|
await this.db.none(qf);
|
||||||
await this.db.none(sql.apply, [patch.name]);
|
await this.db.none(sql.apply, [patch.name]);
|
||||||
})
|
})
|
||||||
@ -63,10 +63,10 @@ export class MigrationRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async applied(): Promise<Migration[]> {
|
public async applied(): Promise<Migration[]> {
|
||||||
return this.db.map(sql.applied, [], row => ({
|
return this.db.map(sql.applied, [], (row) => ({
|
||||||
appliedAt: row.applied_at as DateTime,
|
appliedAt: row.applied_at as DateTime,
|
||||||
id: +row.id,
|
id: +row.id,
|
||||||
name: row.name
|
name: row.name,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,14 +22,14 @@ import { IDatabase, IMain } from "pg-promise";
|
|||||||
export class SessionRepository {
|
export class SessionRepository {
|
||||||
private db: IDatabase<any>;
|
private db: IDatabase<any>;
|
||||||
|
|
||||||
constructor(db: IDatabase<any>, pgp: IMain) {
|
constructor(db: IDatabase<any>, _pgp: IMain) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async all(): Promise<Session[]> {
|
public async all(): Promise<Session[]> {
|
||||||
return this.db.map(sql.all, [], row => ({
|
return this.db.map(sql.all, [], (row) => ({
|
||||||
session: row.session,
|
session: row.session,
|
||||||
sid: row.sid
|
sid: row.sid,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,25 +42,25 @@ export class SessionRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async get(sid: string): Promise<Maybe<Session>> {
|
public async get(sid: string): Promise<Maybe<Session>> {
|
||||||
return this.db.oneOrNone(sql.get, [sid]).then(row =>
|
return this.db.oneOrNone(sql.get, [sid]).then((row) =>
|
||||||
row
|
row
|
||||||
? Maybe.Some({
|
? Maybe.Some({
|
||||||
session: row.session,
|
session: row.session,
|
||||||
sid: row.sid
|
sid: row.sid,
|
||||||
})
|
})
|
||||||
: Maybe.None()
|
: Maybe.None()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async length(): Promise<number> {
|
public async length(): Promise<number> {
|
||||||
return this.db.one(sql.length).then(row => +row.length);
|
return this.db.one(sql.length).then((row) => +row.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async set(sid: string, session: SessionData, expiresAt: DateTime) {
|
public async set(sid: string, session: SessionData, expiresAt: DateTime) {
|
||||||
return this.db.none(sql.set, [
|
return this.db.none(sql.set, [
|
||||||
sid,
|
sid,
|
||||||
JSON.stringify(session),
|
JSON.stringify(session),
|
||||||
expiresAt.toSQL()
|
expiresAt.toSQL(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { ScheduleType, Task } from "@kredens/server/db/models";
|
import { Task } from "@kredens/server/db/models";
|
||||||
import { tasks as sql } from "@kredens/server/db/sql";
|
import { tasks as sql } from "@kredens/server/db/sql";
|
||||||
import { IDatabase, IMain } from "pg-promise";
|
import { IDatabase, IMain } from "pg-promise";
|
||||||
|
|
||||||
@ -24,14 +24,14 @@ function rowToTask(row: any): Task {
|
|||||||
name: row.name,
|
name: row.name,
|
||||||
notes: row.notes,
|
notes: row.notes,
|
||||||
schedule: row.schedule,
|
schedule: row.schedule,
|
||||||
createdAt: row.created_at
|
createdAt: row.created_at,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TaskRepository {
|
export class TaskRepository {
|
||||||
private db: IDatabase<any>;
|
private db: IDatabase<any>;
|
||||||
|
|
||||||
constructor(db: IDatabase<any>, pgp: IMain) {
|
constructor(db: IDatabase<any>, _pgp: IMain) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,12 +40,12 @@ export class TaskRepository {
|
|||||||
limit?: number,
|
limit?: number,
|
||||||
offset?: number
|
offset?: number
|
||||||
): Promise<Task[]> {
|
): Promise<Task[]> {
|
||||||
return this.db.map(sql.list, [owner, limit || 10, offset || 0], row =>
|
return this.db.map(sql.list, [owner, limit || 10, offset || 0], (row) =>
|
||||||
rowToTask(row)
|
rowToTask(row)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async count(owner: number): Promise<number> {
|
public async count(owner: number): Promise<number> {
|
||||||
return this.db.one(sql.count, [owner], row => +row.c);
|
return this.db.one(sql.count, [owner], (row) => +row.c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,16 @@ import { IDatabase, IMain } from "pg-promise";
|
|||||||
export class UserRepository {
|
export class UserRepository {
|
||||||
private db: IDatabase<any>;
|
private db: IDatabase<any>;
|
||||||
|
|
||||||
constructor(db: IDatabase<any>, pgp: IMain) {
|
constructor(db: IDatabase<any>, _pgp: IMain) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async login(email: string, password: string): Promise<Maybe<number>> {
|
public async login(email: string, password: string): Promise<Maybe<number>> {
|
||||||
const { id, encryptedPassword } = await this.db
|
const { id, encryptedPassword } = await this.db
|
||||||
.oneOrNone(sql.login, [email])
|
.oneOrNone(sql.login, [email])
|
||||||
.then(user => ({
|
.then((user) => ({
|
||||||
encryptedPassword: user.encrypted_password,
|
encryptedPassword: user.encrypted_password,
|
||||||
id: +user.id
|
id: +user.id,
|
||||||
}));
|
}));
|
||||||
if (id === null) {
|
if (id === null) {
|
||||||
return None();
|
return None();
|
||||||
|
@ -13,34 +13,34 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { requireAuthMiddleware } from "@kredens/server/auth";
|
import { db } from "@kredens/server/db"
|
||||||
import { db } from "@kredens/server/db";
|
import express from "express"
|
||||||
import express from "express";
|
import { requireAuthMiddleware } from "@kredens/server/auth"
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router()
|
||||||
|
|
||||||
function tryInt(v: string, def?: number): number | undefined {
|
function tryInt(v: string, def?: number): number | undefined {
|
||||||
if (v) {
|
if (v) {
|
||||||
const value = parseInt(v, 10);
|
const value = parseInt(v, 10)
|
||||||
return isNaN(value) ? def : value;
|
return isNaN(value) ? def : value
|
||||||
}
|
}
|
||||||
|
|
||||||
return def;
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
router.use(requireAuthMiddleware());
|
router.use(requireAuthMiddleware())
|
||||||
router.get("/tasks", async (req, res, next) => {
|
router.get("/tasks", async (req, res) => {
|
||||||
const limit = tryInt(req.query.limit, 10);
|
const limit = tryInt(req.query.limit, 10)
|
||||||
const offset = tryInt(req.query.offset, 0);
|
const offset = tryInt(req.query.offset, 0)
|
||||||
|
|
||||||
const result = await db.tx(async tx => {
|
const result = await db.tx(async tx => {
|
||||||
const tasks = await tx.tasks.list(req.user.id, limit, offset);
|
const tasks = await tx.tasks.list(req.user.id, limit, offset)
|
||||||
const count = await tx.tasks.count(req.user.id);
|
const count = await tx.tasks.count(req.user.id)
|
||||||
return {
|
return {
|
||||||
tasks,
|
tasks,
|
||||||
count
|
count
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
tasks: result.tasks.map(t => ({
|
tasks: result.tasks.map(t => ({
|
||||||
@ -51,7 +51,7 @@ router.get("/tasks", async (req, res, next) => {
|
|||||||
createdAt: t.createdAt.toISO
|
createdAt: t.createdAt.toISO
|
||||||
})),
|
})),
|
||||||
count: result.count
|
count: result.count
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
export default router;
|
export default router
|
||||||
|
@ -18,11 +18,11 @@ import express from "express";
|
|||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", async (req, res, next) => {
|
router.get("/", async (req, res) => {
|
||||||
res.render("login");
|
res.render("login");
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/", async (req, res, next) => {
|
router.post("/", async (req, res) => {
|
||||||
const userID = await db.users.login(req.body.email, req.body.password);
|
const userID = await db.users.login(req.body.email, req.body.password);
|
||||||
if (userID.isSome()) {
|
if (userID.isSome()) {
|
||||||
req.session.userID = userID.some();
|
req.session.userID = userID.some();
|
||||||
|
@ -13,43 +13,43 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { box, unbox } from "@kredens/server/crypto";
|
import { box, unbox } from "@kredens/server/crypto"
|
||||||
import { db } from "@kredens/server/db";
|
import createHttpError from "http-errors"
|
||||||
import express from "express";
|
import { DateTime } from "luxon"
|
||||||
import createHttpError from "http-errors";
|
import { db } from "@kredens/server/db"
|
||||||
import { DateTime } from "luxon";
|
import express from "express"
|
||||||
|
|
||||||
interface Token {
|
interface Token {
|
||||||
expires: string;
|
expires: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router()
|
||||||
|
|
||||||
router.get("/", async (req, res, next) => {
|
router.get("/", async (req) => {
|
||||||
const token: Token = {
|
const token: Token = {
|
||||||
expires: DateTime.local()
|
expires: DateTime.local()
|
||||||
.plus({ hours: 2 })
|
.plus({ hours: 2 })
|
||||||
.toISO()
|
.toISO()
|
||||||
};
|
}
|
||||||
req.log.info("Token issued", { token: box(token) });
|
req.log.info("Token issued", { token: box(token) })
|
||||||
});
|
})
|
||||||
|
|
||||||
router.post("/", async (req, res, next) => {
|
router.post("/", async (req, res, next) => {
|
||||||
const token: Token = unbox(req.body.token);
|
const token: Token = unbox(req.body.token)
|
||||||
const expired = DateTime.fromISO(token.expires).diffNow();
|
const expired = DateTime.fromISO(token.expires).diffNow()
|
||||||
if (expired.as("milliseconds") < 0) {
|
if (expired.as("milliseconds") < 0) {
|
||||||
next(createHttpError(401));
|
next(createHttpError(401))
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const email: string = req.body.email;
|
const email: string = req.body.email
|
||||||
const password: string = req.body.password;
|
const password: string = req.body.password
|
||||||
|
|
||||||
if (!email || !password || password.length < 8) {
|
if (!email || !password || password.length < 8) {
|
||||||
res.send("Please provide an email and a password longer than 8 characters");
|
res.send("Please provide an email and a password longer than 8 characters")
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
await db.users.create(email, password);
|
await db.users.create(email, password)
|
||||||
});
|
})
|
||||||
|
|
||||||
export default router;
|
export default router
|
||||||
|
@ -17,7 +17,7 @@ import express from "express";
|
|||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get("/", (req, res, next) => {
|
router.get("/", (req, res) => {
|
||||||
res.render("index", { title: "Hey", message: "Hi!" });
|
res.render("index", { title: "Hey", message: "Hi!" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { Store } from "@holdyourwaffle/express-session";
|
|
||||||
import { db } from "@kredens/server/db";
|
|
||||||
import { DateTime, Duration } from "luxon";
|
import { DateTime, Duration } from "luxon";
|
||||||
|
import { db } from "@kredens/server/db";
|
||||||
|
import { Store } from "@holdyourwaffle/express-session";
|
||||||
|
|
||||||
export class PgStore extends Store {
|
export class PgStore extends Store {
|
||||||
private ttl: Duration;
|
private ttl: Duration;
|
||||||
@ -30,8 +30,8 @@ export class PgStore extends Store {
|
|||||||
) {
|
) {
|
||||||
db.sessions
|
db.sessions
|
||||||
.get(sid)
|
.get(sid)
|
||||||
.then(s => cb(null, s.map(ss => ss.session).orNull()))
|
.then((s) => cb(null, s.map((ss) => ss.session).orNull()))
|
||||||
.catch(r => cb(r, null));
|
.catch((r) => cb(r, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(sid: string, session: SessionData, cb?: (err?: any) => void) {
|
public set(sid: string, session: SessionData, cb?: (err?: any) => void) {
|
||||||
@ -39,7 +39,7 @@ export class PgStore extends Store {
|
|||||||
const p = db.sessions.set(sid, session, expiresAt);
|
const p = db.sessions.set(sid, session, expiresAt);
|
||||||
|
|
||||||
if (cb) {
|
if (cb) {
|
||||||
p.then(s => cb(null)).catch(r => cb(r));
|
p.then(() => cb(null)).catch((r) => cb(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ export class PgStore extends Store {
|
|||||||
const p = db.sessions.destroy(sid);
|
const p = db.sessions.destroy(sid);
|
||||||
|
|
||||||
if (cb) {
|
if (cb) {
|
||||||
p.then(s => cb()).catch(r => cb(r));
|
p.then(() => cb()).catch((r) => cb(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ export class PgStore extends Store {
|
|||||||
) {
|
) {
|
||||||
db.sessions
|
db.sessions
|
||||||
.all()
|
.all()
|
||||||
.then(ss => {
|
.then((ss) => {
|
||||||
const sessions: { [sid: string]: SessionData } = {};
|
const sessions: { [sid: string]: SessionData } = {};
|
||||||
|
|
||||||
for (const s of ss) {
|
for (const s of ss) {
|
||||||
@ -65,27 +65,27 @@ export class PgStore extends Store {
|
|||||||
|
|
||||||
cb(null, sessions);
|
cb(null, sessions);
|
||||||
})
|
})
|
||||||
.catch(r => cb(r, null));
|
.catch((r) => cb(r, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public length(cb: (err: any, length: number) => void) {
|
public length(cb: (err: any, length: number) => void) {
|
||||||
db.sessions
|
db.sessions
|
||||||
.length()
|
.length()
|
||||||
.then(l => cb(null, l))
|
.then((l) => cb(null, l))
|
||||||
.catch(r => cb(r, 0));
|
.catch((r) => cb(r, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(cb?: (err?: any) => void) {
|
public clear(cb?: (err?: any) => void) {
|
||||||
const p = db.sessions.clear();
|
const p = db.sessions.clear();
|
||||||
if (cb) {
|
if (cb) {
|
||||||
p.then(() => cb()).catch(r => cb(r));
|
p.then(() => cb()).catch((r) => cb(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public touch(sid: string, session: SessionData, cb?: (err?: any) => void) {
|
public touch(sid: string, session: SessionData, cb?: (err?: any) => void) {
|
||||||
const p = db.sessions.touch(sid, this.getExpiresAt(session));
|
const p = db.sessions.touch(sid, this.getExpiresAt(session));
|
||||||
if (cb) {
|
if (cb) {
|
||||||
p.then(() => cb()).catch(r => cb(r));
|
p.then(() => cb()).catch((r) => cb(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tslint.json",
|
|
||||||
"rules": {
|
|
||||||
"no-implicit-dependencies": [
|
|
||||||
true,
|
|
||||||
["@kredens/server"]
|
|
||||||
],
|
|
||||||
"no-submodule-imports": [
|
|
||||||
true,
|
|
||||||
"@kredens/server"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import webpack from "webpack"; // tslint:disable-line:no-implicit-dependencies
|
import webpack from "webpack";
|
||||||
|
|
||||||
const config: webpack.Configuration = {
|
const config: webpack.Configuration = {
|
||||||
mode: "development",
|
mode: "development",
|
||||||
@ -8,28 +8,28 @@ const config: webpack.Configuration = {
|
|||||||
output: {
|
output: {
|
||||||
filename: "[name].bundle.js",
|
filename: "[name].bundle.js",
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
publicPath: "/assets/"
|
publicPath: "/assets/",
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: "ts-loader",
|
loader: "ts-loader",
|
||||||
test: /\.tsx?$/
|
test: /\.tsx?$/,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".tsx", ".js"],
|
extensions: [".ts", ".tsx", ".js"],
|
||||||
alias: {
|
alias: {
|
||||||
"@kredens": path.resolve(__dirname, "src/")
|
"@kredens": path.resolve(__dirname, "src/"),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
API_URL: JSON.stringify("http://localhost:3000/api/")
|
API_URL: JSON.stringify("http://localhost:3000/api/"),
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user