Compare commits
10 Commits
78addafe18
...
6c20416a83
Author | SHA1 | Date | |
---|---|---|---|
|
6c20416a83 | ||
1415da72df | |||
0bb28ce89a | |||
5c21712344 | |||
82d356ef5e | |||
46a7e07b86 | |||
|
fd335ce5cd | ||
a4f5cf18d8 | |||
e9e1b48970 | |||
0f53063832 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@
|
||||
**/config
|
||||
|
||||
!.prettierrc.json
|
||||
!.insomnia
|
||||
|
8
.insomnia/ApiSpec/spc_8436777c430547adb1085fd68e18eace.yml
Executable file
8
.insomnia/ApiSpec/spc_8436777c430547adb1085fd68e18eace.yml
Executable file
@ -0,0 +1,8 @@
|
||||
_id: spc_8436777c430547adb1085fd68e18eace
|
||||
type: ApiSpec
|
||||
parentId: wrk_01922deddc7342ddb4d070126530214b
|
||||
modified: 1666813426216
|
||||
created: 1666813426216
|
||||
fileName: Rate
|
||||
contents: ""
|
||||
contentType: yaml
|
14
.insomnia/Environment/env_25eaa5dc66424aeabb57ef52fb713da8.yml
Executable file
14
.insomnia/Environment/env_25eaa5dc66424aeabb57ef52fb713da8.yml
Executable file
@ -0,0 +1,14 @@
|
||||
_id: env_25eaa5dc66424aeabb57ef52fb713da8
|
||||
type: Environment
|
||||
parentId: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
|
||||
modified: 1666813483038
|
||||
created: 1666813431942
|
||||
name: local
|
||||
data:
|
||||
URL: http://localhost:8000
|
||||
dataPropertyOrder:
|
||||
"&":
|
||||
- URL
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1666813431942
|
14
.insomnia/Environment/env_589a320c58d54efc8e9ab96f6506ebd0.yml
Executable file
14
.insomnia/Environment/env_589a320c58d54efc8e9ab96f6506ebd0.yml
Executable file
@ -0,0 +1,14 @@
|
||||
_id: env_589a320c58d54efc8e9ab96f6506ebd0
|
||||
type: Environment
|
||||
parentId: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
|
||||
modified: 1666813482405
|
||||
created: 1666813453631
|
||||
name: yayeet.cf
|
||||
data:
|
||||
URL: https://html5.yayeet.cf/api
|
||||
dataPropertyOrder:
|
||||
"&":
|
||||
- URL
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1666813453631
|
11
.insomnia/Environment/env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a.yml
Executable file
11
.insomnia/Environment/env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a.yml
Executable file
@ -0,0 +1,11 @@
|
||||
_id: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
|
||||
type: Environment
|
||||
parentId: wrk_01922deddc7342ddb4d070126530214b
|
||||
modified: 1666813430220
|
||||
created: 1666813426222
|
||||
name: Base Environment
|
||||
data: {}
|
||||
dataPropertyOrder: {}
|
||||
color: null
|
||||
isPrivate: false
|
||||
metaSortKey: 1666813426222
|
21
.insomnia/Request/req_7a775a1b9142457eb390ccd6b2e72f28.yml
Executable file
21
.insomnia/Request/req_7a775a1b9142457eb390ccd6b2e72f28.yml
Executable file
@ -0,0 +1,21 @@
|
||||
_id: req_7a775a1b9142457eb390ccd6b2e72f28
|
||||
type: Request
|
||||
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
modified: 1666813549000
|
||||
created: 1666813535408
|
||||
url: "{{ _.URL }}/user/logout"
|
||||
name: Logout
|
||||
description: ""
|
||||
method: POST
|
||||
body: {}
|
||||
parameters: []
|
||||
headers: []
|
||||
authentication: {}
|
||||
metaSortKey: -1666813492452
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
30
.insomnia/Request/req_b0a828e3ee4d4267bd036b10d6bb1bed.yml
Executable file
30
.insomnia/Request/req_b0a828e3ee4d4267bd036b10d6bb1bed.yml
Executable file
@ -0,0 +1,30 @@
|
||||
_id: req_b0a828e3ee4d4267bd036b10d6bb1bed
|
||||
type: Request
|
||||
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
modified: 1667756731637
|
||||
created: 1666813566609
|
||||
url: "{{ _.URL }}/user/create"
|
||||
name: Create
|
||||
description: ""
|
||||
method: POST
|
||||
body:
|
||||
mimeType: application/json
|
||||
text: |-
|
||||
{
|
||||
"username": "test2",
|
||||
"password": "coucou",
|
||||
"role": "USER"
|
||||
}
|
||||
parameters: []
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
authentication: {}
|
||||
metaSortKey: -1666813492352
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
21
.insomnia/Request/req_bf97a9e369584040ac3a8440c7b2bc7c.yml
Executable file
21
.insomnia/Request/req_bf97a9e369584040ac3a8440c7b2bc7c.yml
Executable file
@ -0,0 +1,21 @@
|
||||
_id: req_bf97a9e369584040ac3a8440c7b2bc7c
|
||||
type: Request
|
||||
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
modified: 1666813598408
|
||||
created: 1666813551357
|
||||
url: "{{ _.URL }}/user/read/ff08bc79-ba76-432d-9709-34eefbc462eb"
|
||||
name: Read
|
||||
description: ""
|
||||
method: GET
|
||||
body: {}
|
||||
parameters: []
|
||||
headers: []
|
||||
authentication: {}
|
||||
metaSortKey: -1666813492402
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
30
.insomnia/Request/req_dbbe63eee56d439bb93f4c4929fcbfb2.yml
Executable file
30
.insomnia/Request/req_dbbe63eee56d439bb93f4c4929fcbfb2.yml
Executable file
@ -0,0 +1,30 @@
|
||||
_id: req_dbbe63eee56d439bb93f4c4929fcbfb2
|
||||
type: Request
|
||||
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
modified: 1667756736645
|
||||
created: 1666813492501
|
||||
url: "{{ _.URL }}/user/login/"
|
||||
name: Login
|
||||
description: ""
|
||||
method: POST
|
||||
body:
|
||||
mimeType: application/json
|
||||
text: |-
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "motdepasse"
|
||||
}
|
||||
parameters: []
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
id: pair_32919a49053545f5b23698f4c5724a56
|
||||
authentication: {}
|
||||
metaSortKey: -1666813492502
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
28
.insomnia/Request/req_f2d435a1ee5b47b1b7b6e2be9db8a8bb.yml
Executable file
28
.insomnia/Request/req_f2d435a1ee5b47b1b7b6e2be9db8a8bb.yml
Executable file
@ -0,0 +1,28 @@
|
||||
_id: req_f2d435a1ee5b47b1b7b6e2be9db8a8bb
|
||||
type: Request
|
||||
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
modified: 1667756731065
|
||||
created: 1667753525832
|
||||
url: "{{ _.URL }}/user/update/ff08bc79-ba76-432d-9709-34eefbc462eb"
|
||||
name: Update
|
||||
description: ""
|
||||
method: PATCH
|
||||
body:
|
||||
mimeType: application/json
|
||||
text: |-
|
||||
{
|
||||
"username": "admin2"
|
||||
}
|
||||
parameters: []
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
authentication: {}
|
||||
metaSortKey: -1666813492302
|
||||
isPrivate: false
|
||||
settingStoreCookies: true
|
||||
settingSendCookies: true
|
||||
settingDisableRenderRequestBody: false
|
||||
settingEncodeUrl: true
|
||||
settingRebuildPath: true
|
||||
settingFollowRedirects: global
|
10
.insomnia/RequestGroup/fld_c78e326c656f4411b8899877dd4f3b9c.yml
Executable file
10
.insomnia/RequestGroup/fld_c78e326c656f4411b8899877dd4f3b9c.yml
Executable file
@ -0,0 +1,10 @@
|
||||
_id: fld_c78e326c656f4411b8899877dd4f3b9c
|
||||
type: RequestGroup
|
||||
parentId: wrk_01922deddc7342ddb4d070126530214b
|
||||
modified: 1666813489256
|
||||
created: 1666813489256
|
||||
name: User
|
||||
description: ""
|
||||
environment: {}
|
||||
environmentPropertyOrder: null
|
||||
metaSortKey: -1666813489256
|
8
.insomnia/Workspace/wrk_01922deddc7342ddb4d070126530214b.yml
Executable file
8
.insomnia/Workspace/wrk_01922deddc7342ddb4d070126530214b.yml
Executable file
@ -0,0 +1,8 @@
|
||||
_id: wrk_01922deddc7342ddb4d070126530214b
|
||||
type: Workspace
|
||||
parentId: null
|
||||
modified: 1666813426216
|
||||
created: 1666813426216
|
||||
name: Rate
|
||||
description: ""
|
||||
scope: design
|
@ -1,19 +1,19 @@
|
||||
import './paths';
|
||||
import Server from './framework/express/server';
|
||||
import ip from 'ip';
|
||||
import UserModel from './framework/mongo/user';
|
||||
import { MongoClient } from 'mongodb';
|
||||
import ip from 'ip';
|
||||
|
||||
import Server from './framework/express/server';
|
||||
import UserModel from './framework/mongo/user';
|
||||
import { Config } from './config';
|
||||
import { exit, env } from 'process';
|
||||
|
||||
export type Services = {
|
||||
userModel: UserModel;
|
||||
};
|
||||
|
||||
const configFile = env.CONFIGFILE;
|
||||
const configFile = process.env.CONFIGFILE;
|
||||
if (configFile === undefined) {
|
||||
console.log('env var CONFIGFILE not set');
|
||||
exit(1);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = new Config(configFile);
|
||||
@ -27,6 +27,13 @@ const services: Services = {
|
||||
|
||||
const server = new Server(config.server, config.mongo, services);
|
||||
|
||||
process.on('SIGINT', async () => {
|
||||
console.log('\nClosing Api...');
|
||||
await mongo.close();
|
||||
await server.close();
|
||||
process.exit();
|
||||
});
|
||||
|
||||
server.start(() =>
|
||||
console.log(
|
||||
`Running on http://127.0.0.1:${config.server.port} http://${ip.address()}:${
|
||||
|
@ -16,6 +16,15 @@ export class Config {
|
||||
|
||||
constructor(configFile: string) {
|
||||
const config = JSON.parse(readFileSync(configFile).toString()) as Config;
|
||||
if (
|
||||
config.mongo.dbName === undefined ||
|
||||
config.mongo.uri === undefined ||
|
||||
config.server.origin === undefined ||
|
||||
config.server.port === undefined
|
||||
) {
|
||||
console.log('Error in Config File');
|
||||
process.exit(1);
|
||||
}
|
||||
this.server = config.server;
|
||||
this.mongo = config.mongo;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
UserRoles,
|
||||
UserWithPasswordCtor,
|
||||
} from '@core';
|
||||
import { generateHash } from '../functions/password';
|
||||
import { getHashedPassword } from '../functions/password';
|
||||
import { Entity } from './entity';
|
||||
|
||||
export class User extends Entity implements UserInfo {
|
||||
@ -34,7 +34,7 @@ export class UserWithPassword extends User implements UserInfoWithPassword {
|
||||
constructor(raw: UserWithPasswordCtor) {
|
||||
super(raw);
|
||||
|
||||
this.password = generateHash(this.uuid, raw.password || '');
|
||||
this.password = getHashedPassword(this.uuid, raw.password || '');
|
||||
}
|
||||
|
||||
Info(): UserInfoWithPassword {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ErrorRequestHandler, Request, RequestHandler } from 'express';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { validationResult } from 'express-validator';
|
||||
import { validationResult, matchedData } from 'express-validator';
|
||||
import { UserInfo, UserRoles } from '@core';
|
||||
|
||||
declare module 'express-session' {
|
||||
@ -9,22 +9,22 @@ declare module 'express-session' {
|
||||
}
|
||||
}
|
||||
|
||||
export function getId(req: Request): string {
|
||||
return req.header('request-id') || 'unknown';
|
||||
export function getRequestId(req: Request): string {
|
||||
return req.header('x-request-id') || 'unknown';
|
||||
}
|
||||
|
||||
export function RequestId(): RequestHandler {
|
||||
return (req, res, next) => {
|
||||
req.headers['request-id'] = randomUUID();
|
||||
req.headers['x-request-id'] = randomUUID();
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
export function CheckPermissions(): RequestHandler {
|
||||
function getResourceId(req: Request): string | null {
|
||||
function getResourceId(req: Request): string | undefined {
|
||||
if (req.params.uuid) return req.params.uuid;
|
||||
if (req.body.uuid) return req.body.uuid;
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function canAccessRessource(user: UserInfo, uuid: string): boolean {
|
||||
@ -34,35 +34,39 @@ export function CheckPermissions(): RequestHandler {
|
||||
|
||||
return (req, res, next) => {
|
||||
if (!req.session.user) {
|
||||
next({ status: 401, messsage: 'Unauthorized' });
|
||||
return;
|
||||
return next({ status: 401, messsage: 'Unauthorized' });
|
||||
}
|
||||
|
||||
if (req.session.user.role === UserRoles.ADMIN) {
|
||||
next();
|
||||
return;
|
||||
return next();
|
||||
}
|
||||
|
||||
const ressourceId = getResourceId(req);
|
||||
if (!ressourceId) {
|
||||
next({ status: 403, messsage: 'Forbidden' });
|
||||
return;
|
||||
}
|
||||
if (canAccessRessource(req.session.user, ressourceId)) {
|
||||
next();
|
||||
return;
|
||||
} else {
|
||||
next({ status: 403, messsage: 'Forbidden' });
|
||||
return;
|
||||
return next({ status: 403, messsage: 'Forbidden' });
|
||||
}
|
||||
|
||||
next({ status: 401, messsage: 'Unauthorized' });
|
||||
if (canAccessRessource(req.session.user, ressourceId)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
next({ status: 403, messsage: 'Forbidden' });
|
||||
};
|
||||
}
|
||||
|
||||
export function SchemaValidator(): RequestHandler {
|
||||
export function ValidateSchema(): RequestHandler {
|
||||
return (req, res, next) => {
|
||||
const error = validationResult(req);
|
||||
|
||||
const oldBody = req.body;
|
||||
req.body = matchedData(req, { locations: ['body'] });
|
||||
|
||||
if (JSON.stringify(oldBody) !== JSON.stringify(req.body))
|
||||
return next({
|
||||
status: 422,
|
||||
message: 'Unprocessable Entity',
|
||||
});
|
||||
|
||||
error.isEmpty()
|
||||
? next()
|
||||
: next({
|
||||
@ -76,6 +80,6 @@ export function ErrorHandler(): ErrorRequestHandler {
|
||||
return (error, req, res, next) => {
|
||||
error.status
|
||||
? res.status(error.status).send(error)
|
||||
: res.status(500).send(error);
|
||||
: res.status(500).send({ status: 500, message: error.message });
|
||||
};
|
||||
}
|
||||
|
@ -36,3 +36,21 @@ export const CreateUserSchema = () =>
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const UpdateUserSchema = () =>
|
||||
checkSchema({
|
||||
username: {
|
||||
isString: true,
|
||||
optional: true,
|
||||
},
|
||||
password: {
|
||||
isString: true,
|
||||
optional: true,
|
||||
},
|
||||
role: {
|
||||
isIn: {
|
||||
options: [Object.values(UserRoles)],
|
||||
},
|
||||
optional: true,
|
||||
},
|
||||
});
|
||||
|
@ -1,15 +1,18 @@
|
||||
import express, { Express } from 'express';
|
||||
import cors from 'cors';
|
||||
import session from 'express-session';
|
||||
import MongoStore from 'connect-mongo';
|
||||
import { randomUUID } from 'crypto';
|
||||
import * as http from 'http';
|
||||
|
||||
import { Routes } from './router';
|
||||
import { RequestId, ErrorHandler } from './middleware';
|
||||
import { Services } from '../../app';
|
||||
import { MongoConfig, ServerConfig } from '../../config';
|
||||
import { randomUUID } from 'crypto';
|
||||
import MongoStore from 'connect-mongo';
|
||||
|
||||
class Server {
|
||||
private app: Express;
|
||||
private server: http.Server;
|
||||
private config: ServerConfig;
|
||||
|
||||
constructor(
|
||||
@ -20,6 +23,7 @@ class Server {
|
||||
this.config = config;
|
||||
|
||||
this.app = express();
|
||||
this.app.disable('x-powered-by');
|
||||
this.app.use(express.json());
|
||||
this.app.use(
|
||||
cors({
|
||||
@ -53,7 +57,16 @@ class Server {
|
||||
}
|
||||
|
||||
start(func: () => void): void {
|
||||
this.app.listen(this.config.port, func);
|
||||
this.server = this.app.listen(this.config.port, func);
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.server.close((error) => {
|
||||
if (error) reject(error);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,31 @@
|
||||
import { RequestHandler, Router } from 'express';
|
||||
import { Services } from '../../app';
|
||||
import { CreateUser, ReadUser, LoginUser } from '../../functions/user';
|
||||
import {
|
||||
CreateUser,
|
||||
ReadUser,
|
||||
LoginUser,
|
||||
UpdateUser,
|
||||
} from '../../functions/user';
|
||||
import {
|
||||
LoginUserSchema,
|
||||
CreateUserSchema,
|
||||
ReadUserSchema,
|
||||
LogoutUserSchema,
|
||||
UpdateUserSchema,
|
||||
} from './schema/user';
|
||||
import { CheckPermissions, getId, SchemaValidator } from './middleware';
|
||||
import { CheckPermissions, getRequestId, ValidateSchema } from './middleware';
|
||||
|
||||
function LoginHandler(services: Services): RequestHandler {
|
||||
const login = LoginUser(services);
|
||||
|
||||
return async (req, res, next) => {
|
||||
const user = await login(getId(req), req.body);
|
||||
user ? (req.session.user = user) : (req.session.user = null);
|
||||
user
|
||||
? res.status(200).send(user)
|
||||
: next({ status: 401, message: 'wrong username or password' });
|
||||
try {
|
||||
const user = await login(getRequestId(req), req.body);
|
||||
user ? (req.session.user = user) : (req.session.user = null);
|
||||
res.status(200).send(user);
|
||||
} catch (error) {
|
||||
next({ status: 401, message: 'wrong username or password' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -27,7 +35,7 @@ function LogoutHandler(services: Services): RequestHandler {
|
||||
req.session.user = null;
|
||||
res.status(204).send();
|
||||
} else {
|
||||
next({ status: 401, message: 'not logged in' });
|
||||
next({ status: 401, message: 'Not Logged In' });
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -36,8 +44,12 @@ function CreateHandler(services: Services): RequestHandler {
|
||||
const createUser = CreateUser(services);
|
||||
|
||||
return async (req, res, next) => {
|
||||
const user = await createUser(getId(req), req.body);
|
||||
user ? res.status(201).send(user) : next();
|
||||
try {
|
||||
const user = await createUser(getRequestId(req), req.body);
|
||||
res.status(201).send(user);
|
||||
} catch (error) {
|
||||
next({ status: 409, message: 'User Already Exists' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -45,10 +57,29 @@ function ReadHandler(services: Services): RequestHandler {
|
||||
const readUser = ReadUser(services);
|
||||
|
||||
return async (req, res, next) => {
|
||||
const user = await readUser(getId(req), req.params.uuid);
|
||||
user
|
||||
? res.status(200).send(user)
|
||||
: next({ status: 404, message: 'user not found' });
|
||||
try {
|
||||
const user = await readUser(getRequestId(req), req.params.uuid);
|
||||
res.status(200).send(user);
|
||||
} catch (error) {
|
||||
next({ status: 404, message: 'User Not Found' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function UpdateHandler(services: Services): RequestHandler {
|
||||
const updateUser = UpdateUser(services);
|
||||
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const user = await updateUser(
|
||||
getRequestId(req),
|
||||
req.params.uuid,
|
||||
req.body,
|
||||
);
|
||||
res.status(200).send(user);
|
||||
} catch (error) {
|
||||
next({ status: 404, message: 'User Not Found' });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -58,30 +89,38 @@ export function Routes(services: Services) {
|
||||
router.post(
|
||||
'/login',
|
||||
LoginUserSchema(),
|
||||
SchemaValidator(),
|
||||
ValidateSchema(),
|
||||
LoginHandler(services),
|
||||
);
|
||||
router.post(
|
||||
'/logout',
|
||||
LogoutUserSchema(),
|
||||
SchemaValidator(),
|
||||
ValidateSchema(),
|
||||
LogoutHandler(services),
|
||||
);
|
||||
router.get(
|
||||
'/read/:uuid',
|
||||
ReadUserSchema(),
|
||||
SchemaValidator(),
|
||||
CheckPermissions(),
|
||||
ReadUserSchema(),
|
||||
ValidateSchema(),
|
||||
ReadHandler(services),
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/create',
|
||||
CreateUserSchema(),
|
||||
SchemaValidator(),
|
||||
CheckPermissions(),
|
||||
CreateUserSchema(),
|
||||
ValidateSchema(),
|
||||
CreateHandler(services),
|
||||
);
|
||||
|
||||
router.patch(
|
||||
'/update/:uuid',
|
||||
CheckPermissions(),
|
||||
UpdateUserSchema(),
|
||||
ValidateSchema(),
|
||||
UpdateHandler(services),
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Collection, Db } from 'mongodb';
|
||||
import { LoginUserBody } from '../../../../core/src/user';
|
||||
import { LoginUserBody, UpdateUserBody } from '@core';
|
||||
import { User, UserWithPassword } from '../../entities/user';
|
||||
import log from '../../functions/logger';
|
||||
import { generateHash } from '../../functions/password';
|
||||
import { log } from '../../functions/logger';
|
||||
import { getHashedPassword } from '../../functions/password';
|
||||
|
||||
class UserModel {
|
||||
private collection: Collection<User>;
|
||||
@ -11,42 +11,87 @@ class UserModel {
|
||||
this.collection = db.collection<User>('users');
|
||||
}
|
||||
|
||||
public async login(tracker: string, data: LoginUserBody) {
|
||||
public async login(tracker: string, data: LoginUserBody): Promise<User> {
|
||||
const checkUser = await this.collection.findOne({
|
||||
username: data.username,
|
||||
});
|
||||
if (checkUser === null) {
|
||||
if (!checkUser) {
|
||||
log(tracker, 'User Not Found');
|
||||
return null;
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const user = await this.collection.findOne({
|
||||
const userDocument = await this.collection.findOne({
|
||||
uuid: checkUser.uuid,
|
||||
password: generateHash(checkUser.uuid, data.password),
|
||||
password: getHashedPassword(checkUser.uuid, data.password),
|
||||
});
|
||||
if (user === null) {
|
||||
if (!userDocument) {
|
||||
log(tracker, 'Wrong Password');
|
||||
return null;
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const user = new User(userDocument);
|
||||
log(tracker, 'LOG IN', user);
|
||||
return new User(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public async create(tracker: string, user: UserWithPassword) {
|
||||
await this.collection.insertOne(user);
|
||||
log(tracker, 'CREATE USER', user);
|
||||
return this.read(tracker, user.uuid);
|
||||
}
|
||||
|
||||
public async read(tracker: string, uuid: string) {
|
||||
const user = await this.collection.findOne({ uuid });
|
||||
if (user === null) {
|
||||
log(tracker, 'User Not Found');
|
||||
return null;
|
||||
public async create(
|
||||
tracker: string,
|
||||
userInfo: UserWithPassword,
|
||||
): Promise<User> {
|
||||
const checkUser = await this.collection.findOne({
|
||||
username: userInfo.username,
|
||||
});
|
||||
if (checkUser) {
|
||||
log(tracker, 'User Already Exists');
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
await this.collection.insertOne(userInfo);
|
||||
|
||||
const user = await this.read(tracker, userInfo.uuid);
|
||||
log(tracker, 'CREATE USER', user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public async read(tracker: string, uuid: string): Promise<User> {
|
||||
const userDocument = await this.collection.findOne({ uuid });
|
||||
if (!userDocument) {
|
||||
log(tracker, 'User Not Found');
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const user = new User(userDocument);
|
||||
log(tracker, 'READ USER', user);
|
||||
return new User(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public async update(
|
||||
tracker: string,
|
||||
uuid: string,
|
||||
userInfo: UpdateUserBody,
|
||||
): Promise<User> {
|
||||
const checkUser = await this.collection.findOne({ uuid });
|
||||
if (!checkUser) {
|
||||
log(tracker, 'User Does Not Exist');
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (userInfo.password)
|
||||
userInfo.password = getHashedPassword(uuid, userInfo.password);
|
||||
|
||||
await this.collection.updateOne(
|
||||
{ uuid },
|
||||
{
|
||||
$set: {
|
||||
...userInfo,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const user = await this.read(tracker, uuid);
|
||||
log(tracker, 'UPDATE USER', user);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
export function log(tracker: string, ...message: unknown[]) {
|
||||
message.forEach((obj, index) => {
|
||||
try {
|
||||
message[index] = JSON.stringify(obj);
|
||||
} catch {}
|
||||
});
|
||||
if (message)
|
||||
message.forEach((obj, index) => {
|
||||
try {
|
||||
message[index] = JSON.stringify(obj);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
tracker ? console.log(`[${tracker}]`, ...message) : console.log(...message);
|
||||
message ? console.log(`[${tracker}]`, ...message) : console.log(tracker);
|
||||
}
|
||||
|
||||
export default log;
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
export function getHashedPassword(uuid: string, password: string) {
|
||||
return generateHash(uuid, password);
|
||||
}
|
||||
|
||||
export function generateHash(...values: string[]) {
|
||||
return createHash('sha256').update(values.join('')).digest('hex');
|
||||
}
|
||||
|
@ -1,36 +1,47 @@
|
||||
import { CreateUserBody, LoginUserBody, UserInfo } from '@core';
|
||||
import { CreateUserBody, LoginUserBody, UserInfo, UpdateUserBody } from '@core';
|
||||
import { Services } from '../app';
|
||||
import { UserWithPassword } from '../entities/user';
|
||||
|
||||
export function LoginUser(
|
||||
services: Services,
|
||||
): (tracker: string, raw: LoginUserBody) => Promise<UserInfo | null> {
|
||||
): (tracker: string, raw: LoginUserBody) => Promise<UserInfo> {
|
||||
const { userModel } = services;
|
||||
|
||||
return async (tracker, raw) => {
|
||||
const user = await userModel.login(tracker, raw);
|
||||
return user ? user.Info() : null;
|
||||
return user.Info();
|
||||
};
|
||||
}
|
||||
|
||||
export function CreateUser(
|
||||
services: Services,
|
||||
): (tracker: string, raw: CreateUserBody) => Promise<UserInfo | null> {
|
||||
): (tracker: string, raw: CreateUserBody) => Promise<UserInfo> {
|
||||
const { userModel } = services;
|
||||
|
||||
return async (tracker, raw) => {
|
||||
const user = await userModel.create(tracker, new UserWithPassword(raw));
|
||||
return user ? user.Info() : null;
|
||||
return user.Info();
|
||||
};
|
||||
}
|
||||
|
||||
export function ReadUser(
|
||||
services: Services,
|
||||
): (tracker: string, uuid: string) => Promise<UserInfo | null> {
|
||||
): (tracker: string, uuid: string) => Promise<UserInfo> {
|
||||
const { userModel } = services;
|
||||
|
||||
return async (tracker, uuid) => {
|
||||
const user = await userModel.read(tracker, uuid);
|
||||
return user ? user.Info() : null;
|
||||
return user.Info();
|
||||
};
|
||||
}
|
||||
|
||||
export function UpdateUser(
|
||||
services: Services,
|
||||
): (tracker: string, uuid: string, raw: UpdateUserBody) => Promise<UserInfo> {
|
||||
const { userModel } = services;
|
||||
|
||||
return async (tracker, uuid, raw) => {
|
||||
const user = await userModel.update(tracker, uuid, raw);
|
||||
return user.Info();
|
||||
};
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ export type CreateUserBody = {
|
||||
role: keyof typeof UserRoles;
|
||||
};
|
||||
|
||||
export type UpdateUserBody = Partial<Omit<UserInfoWithPassword, 'uuid'>>;
|
||||
|
||||
export type LoginUserBody = {
|
||||
username: string;
|
||||
password: string;
|
||||
|
0
scripts/deploy.sh
Executable file → Normal file
0
scripts/deploy.sh
Executable file → Normal file
26
scripts/tools.py
Executable file → Normal file
26
scripts/tools.py
Executable file → Normal file
@ -1,6 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import sys
|
||||
from os import chdir, path
|
||||
from sys import argv
|
||||
from subprocess import run, PIPE
|
||||
from multiprocessing import Process
|
||||
|
||||
apps = ['core', 'api', 'www']
|
||||
commands = {
|
||||
@ -14,19 +16,29 @@ def print_commands():
|
||||
print('Available commands:', [c for c in commands])
|
||||
|
||||
|
||||
def run_command_in_app(app: str, command: str):
|
||||
chdir(app)
|
||||
result = run(command.split(' '), stdout=PIPE, stderr=PIPE, text=True)
|
||||
|
||||
status = 'DONE' if result.returncode == 0 else 'ERROR'
|
||||
print('%s:\t%s' % (app, status))
|
||||
if status == 'ERROR':
|
||||
print(result.stdout, result.stderr)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
if len(argv) < 2:
|
||||
print_commands()
|
||||
exit()
|
||||
|
||||
cmd = sys.argv[1]
|
||||
cmd = argv[1]
|
||||
if cmd not in commands:
|
||||
print('Command \'%s\' not available' % cmd)
|
||||
print_commands()
|
||||
exit()
|
||||
|
||||
chdir(path.join(path.dirname(path.realpath(__file__)), '..'))
|
||||
|
||||
print('Running \'%s\' on %d apps: %s' % (commands[cmd], len(apps), apps))
|
||||
for app in apps:
|
||||
os.chdir(app)
|
||||
os.system(commands[cmd])
|
||||
os.chdir('..')
|
||||
Process(target=run_command_in_app, args=(app, commands[cmd])).start()
|
||||
|
1282
www/package-lock.json
generated
1282
www/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
"author": "Yanis Rigaudeau - Axel Barault",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"build": "rollup -c --failAfterWarnings",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv public --no-clear --host --single",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
@ -18,6 +18,7 @@
|
||||
"@rollup/plugin-typescript": "^8.0.0",
|
||||
"@tsconfig/svelte": "^2.0.0",
|
||||
"@types/three": "^0.144.0",
|
||||
"@types/w3c-image-capture": "^1.0.7",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier-plugin-svelte": "^2.8.0",
|
||||
"rollup": "^2.3.4",
|
||||
@ -32,6 +33,7 @@
|
||||
"typescript": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ar-js-org/ar.js": "^3.4.3",
|
||||
"papercss": "^1.8.3",
|
||||
"sirv-cli": "^2.0.0",
|
||||
"spaper": "^0.9.6",
|
||||
|
BIN
www/public/models/dingus_the_cat.glb
Normal file
BIN
www/public/models/dingus_the_cat.glb
Normal file
Binary file not shown.
195
www/public/patterns/patt.hiro
Normal file
195
www/public/patterns/patt.hiro
Normal file
@ -0,0 +1,195 @@
|
||||
234 235 240 233 240 234 240 235 240 237 240 238 240 240 240 232
|
||||
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
|
||||
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
231 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
225 149 240 240 186 216 225 174 240 240 240 237 238 240 240 240
|
||||
150 107 238 231 75 208 115 147 238 228 223 226 237 180 226 240
|
||||
150 62 181 213 62 187 113 169 197 72 29 237 120 50 53 207
|
||||
149 63 47 78 53 184 113 101 142 5 150 150 45 217 186 83
|
||||
121 84 220 222 58 180 121 92 128 109 237 124 155 232 161 64
|
||||
149 71 240 240 76 210 98 109 122 108 240 129 51 119 161 155
|
||||
149 186 240 240 98 219 135 152 207 191 236 227 152 77 175 209
|
||||
235 235 240 233 240 234 240 235 240 236 240 238 240 240 240 240
|
||||
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
225 156 240 240 186 216 225 186 240 240 240 240 240 240 240 240
|
||||
150 117 240 231 72 206 115 162 240 232 223 237 240 180 226 240
|
||||
150 74 187 213 51 184 103 168 197 78 29 237 120 50 53 216
|
||||
144 77 51 74 61 184 106 101 142 5 150 152 52 217 186 85
|
||||
117 89 219 219 65 184 121 92 128 100 236 125 156 240 170 73
|
||||
148 71 240 240 76 210 109 109 121 99 240 137 51 120 166 164
|
||||
140 186 240 240 98 220 150 156 207 192 236 230 152 77 176 212
|
||||
234 235 240 233 240 234 240 235 240 236 240 238 240 240 240 233
|
||||
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
|
||||
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
235 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
225 156 240 240 182 212 225 180 240 240 240 240 240 240 240 240
|
||||
150 116 238 228 66 205 115 151 238 236 225 240 240 180 226 240
|
||||
156 84 186 211 47 184 109 170 200 92 30 240 120 50 53 216
|
||||
147 83 51 73 50 184 106 110 148 17 151 150 45 217 186 85
|
||||
127 98 219 219 58 179 109 101 128 107 237 125 155 240 163 72
|
||||
155 86 240 240 76 201 85 108 121 95 232 137 51 118 153 155
|
||||
149 189 240 240 98 220 141 154 206 178 235 230 152 77 175 209
|
||||
|
||||
232 228 239 240 240 240 240 240 240 240 240 207 83 64 155 209
|
||||
240 240 240 240 240 240 240 240 240 240 226 53 186 161 161 175
|
||||
240 240 240 240 240 240 240 240 240 240 180 50 217 232 119 77
|
||||
240 240 240 240 240 240 240 240 240 238 237 120 45 155 51 152
|
||||
238 240 240 240 240 240 240 240 240 237 226 237 150 124 129 227
|
||||
240 240 240 240 240 240 240 240 240 240 223 29 150 237 240 236
|
||||
237 240 240 240 240 240 240 240 240 240 228 72 5 109 108 191
|
||||
240 240 240 240 240 240 240 240 240 240 238 197 142 128 122 207
|
||||
235 240 240 240 240 240 240 240 240 174 147 169 101 92 109 152
|
||||
240 240 240 240 240 240 240 240 240 225 115 113 113 121 98 135
|
||||
234 240 240 240 240 240 240 240 240 216 208 187 184 180 210 219
|
||||
240 240 240 240 240 240 240 240 240 186 75 62 53 58 76 98
|
||||
233 240 240 240 240 240 240 240 240 240 231 213 78 222 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 238 181 47 220 240 240
|
||||
235 240 240 240 240 240 240 240 240 149 107 62 63 84 71 186
|
||||
234 229 227 240 236 234 236 231 229 225 150 150 149 121 149 149
|
||||
240 240 240 240 240 240 240 240 240 240 240 216 85 73 164 212
|
||||
240 240 240 240 240 240 240 240 240 240 226 53 186 170 166 176
|
||||
240 240 240 240 240 240 240 240 240 240 180 50 217 240 120 77
|
||||
240 240 240 240 240 240 240 240 240 240 240 120 52 156 51 152
|
||||
238 240 240 240 240 240 240 240 240 240 237 237 152 125 137 230
|
||||
240 240 240 240 240 240 240 240 240 240 223 29 150 236 240 236
|
||||
236 240 240 240 240 240 240 240 240 240 232 78 5 100 99 192
|
||||
240 240 240 240 240 240 240 240 240 240 240 197 142 128 121 207
|
||||
235 240 240 240 240 240 240 240 240 186 162 168 101 92 109 156
|
||||
240 240 240 240 240 240 240 240 240 225 115 103 106 121 109 150
|
||||
234 240 240 240 240 240 240 240 240 216 206 184 184 184 210 220
|
||||
240 240 240 240 240 240 240 240 240 186 72 51 61 65 76 98
|
||||
233 240 240 240 240 240 240 240 240 240 231 213 74 219 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 240 187 51 219 240 240
|
||||
235 240 240 240 240 240 240 240 240 156 117 74 77 89 71 186
|
||||
235 229 227 240 236 234 236 232 229 225 150 150 144 117 148 140
|
||||
233 239 240 240 240 240 240 240 240 240 240 216 85 72 155 209
|
||||
240 240 240 240 240 240 240 240 240 240 226 53 186 163 153 175
|
||||
240 240 240 240 240 240 240 240 240 240 180 50 217 240 118 77
|
||||
240 240 240 240 240 240 240 240 240 240 240 120 45 155 51 152
|
||||
238 240 240 240 240 240 240 240 240 240 240 240 150 125 137 230
|
||||
240 240 240 240 240 240 240 240 240 240 225 30 151 237 232 235
|
||||
236 240 240 240 240 240 240 240 240 240 236 92 17 107 95 178
|
||||
240 240 240 240 240 240 240 240 240 240 238 200 148 128 121 206
|
||||
235 240 240 240 240 240 240 240 240 180 151 170 110 101 108 154
|
||||
240 240 240 240 240 240 240 240 240 225 115 109 106 109 85 141
|
||||
234 240 240 240 240 240 240 240 240 212 205 184 184 179 201 220
|
||||
240 240 240 240 240 240 240 240 240 182 66 47 50 58 76 98
|
||||
233 240 240 240 240 240 240 240 240 240 228 211 73 219 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 238 186 51 219 240 240
|
||||
235 240 240 240 240 240 240 240 240 156 116 84 83 98 86 189
|
||||
234 229 227 240 234 232 235 232 228 225 150 156 147 127 155 149
|
||||
|
||||
209 175 77 152 227 236 191 207 152 135 219 98 240 240 186 149
|
||||
155 161 119 51 129 240 108 122 109 98 210 76 240 240 71 149
|
||||
64 161 232 155 124 237 109 128 92 121 180 58 222 220 84 121
|
||||
83 186 217 45 150 150 5 142 101 113 184 53 78 47 63 149
|
||||
207 53 50 120 237 29 72 197 169 113 187 62 213 181 62 150
|
||||
240 226 180 237 226 223 228 238 147 115 208 75 231 238 107 150
|
||||
240 240 240 238 237 240 240 240 174 225 216 186 240 240 149 225
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 231
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
|
||||
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
|
||||
232 240 240 240 238 240 237 240 235 240 234 240 233 240 235 234
|
||||
212 176 77 152 230 236 192 207 156 150 220 98 240 240 186 140
|
||||
164 166 120 51 137 240 99 121 109 109 210 76 240 240 71 148
|
||||
73 170 240 156 125 236 100 128 92 121 184 65 219 219 89 117
|
||||
85 186 217 52 152 150 5 142 101 106 184 61 74 51 77 144
|
||||
216 53 50 120 237 29 78 197 168 103 184 51 213 187 74 150
|
||||
240 226 180 240 237 223 232 240 162 115 206 72 231 240 117 150
|
||||
240 240 240 240 240 240 240 240 186 225 216 186 240 240 156 225
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
|
||||
240 240 240 240 238 240 236 240 235 240 234 240 233 240 235 235
|
||||
209 175 77 152 230 235 178 206 154 141 220 98 240 240 189 149
|
||||
155 153 118 51 137 232 95 121 108 85 201 76 240 240 86 155
|
||||
72 163 240 155 125 237 107 128 101 109 179 58 219 219 98 127
|
||||
85 186 217 45 150 151 17 148 110 106 184 50 73 51 83 147
|
||||
216 53 50 120 240 30 92 200 170 109 184 47 211 186 84 156
|
||||
240 226 180 240 240 225 236 238 151 115 205 66 228 238 116 150
|
||||
240 240 240 240 240 240 240 240 180 225 212 182 240 240 156 225
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 235
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
|
||||
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
|
||||
233 240 240 240 238 240 236 240 235 240 234 240 233 240 235 234
|
||||
|
||||
149 149 121 149 150 150 225 229 231 236 234 236 240 227 229 234
|
||||
186 71 84 63 62 107 149 240 240 240 240 240 240 240 240 235
|
||||
240 240 220 47 181 238 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 222 78 213 231 240 240 240 240 240 240 240 240 240 233
|
||||
98 76 58 53 62 75 186 240 240 240 240 240 240 240 240 240
|
||||
219 210 180 184 187 208 216 240 240 240 240 240 240 240 240 234
|
||||
135 98 121 113 113 115 225 240 240 240 240 240 240 240 240 240
|
||||
152 109 92 101 169 147 174 240 240 240 240 240 240 240 240 235
|
||||
207 122 128 142 197 238 240 240 240 240 240 240 240 240 240 240
|
||||
191 108 109 5 72 228 240 240 240 240 240 240 240 240 240 237
|
||||
236 240 237 150 29 223 240 240 240 240 240 240 240 240 240 240
|
||||
227 129 124 150 237 226 237 240 240 240 240 240 240 240 240 238
|
||||
152 51 155 45 120 237 238 240 240 240 240 240 240 240 240 240
|
||||
77 119 232 217 50 180 240 240 240 240 240 240 240 240 240 240
|
||||
175 161 161 186 53 226 240 240 240 240 240 240 240 240 240 240
|
||||
209 155 64 83 207 240 240 240 240 240 240 240 240 239 228 232
|
||||
140 148 117 144 150 150 225 229 232 236 234 236 240 227 229 235
|
||||
186 71 89 77 74 117 156 240 240 240 240 240 240 240 240 235
|
||||
240 240 219 51 187 240 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 219 74 213 231 240 240 240 240 240 240 240 240 240 233
|
||||
98 76 65 61 51 72 186 240 240 240 240 240 240 240 240 240
|
||||
220 210 184 184 184 206 216 240 240 240 240 240 240 240 240 234
|
||||
150 109 121 106 103 115 225 240 240 240 240 240 240 240 240 240
|
||||
156 109 92 101 168 162 186 240 240 240 240 240 240 240 240 235
|
||||
207 121 128 142 197 240 240 240 240 240 240 240 240 240 240 240
|
||||
192 99 100 5 78 232 240 240 240 240 240 240 240 240 240 236
|
||||
236 240 236 150 29 223 240 240 240 240 240 240 240 240 240 240
|
||||
230 137 125 152 237 237 240 240 240 240 240 240 240 240 240 238
|
||||
152 51 156 52 120 240 240 240 240 240 240 240 240 240 240 240
|
||||
77 120 240 217 50 180 240 240 240 240 240 240 240 240 240 240
|
||||
176 166 170 186 53 226 240 240 240 240 240 240 240 240 240 240
|
||||
212 164 73 85 216 240 240 240 240 240 240 240 240 240 240 240
|
||||
149 155 127 147 156 150 225 228 232 235 232 234 240 227 229 234
|
||||
189 86 98 83 84 116 156 240 240 240 240 240 240 240 240 235
|
||||
240 240 219 51 186 238 240 240 240 240 240 240 240 240 240 240
|
||||
240 240 219 73 211 228 240 240 240 240 240 240 240 240 240 233
|
||||
98 76 58 50 47 66 182 240 240 240 240 240 240 240 240 240
|
||||
220 201 179 184 184 205 212 240 240 240 240 240 240 240 240 234
|
||||
141 85 109 106 109 115 225 240 240 240 240 240 240 240 240 240
|
||||
154 108 101 110 170 151 180 240 240 240 240 240 240 240 240 235
|
||||
206 121 128 148 200 238 240 240 240 240 240 240 240 240 240 240
|
||||
178 95 107 17 92 236 240 240 240 240 240 240 240 240 240 236
|
||||
235 232 237 151 30 225 240 240 240 240 240 240 240 240 240 240
|
||||
230 137 125 150 240 240 240 240 240 240 240 240 240 240 240 238
|
||||
152 51 155 45 120 240 240 240 240 240 240 240 240 240 240 240
|
||||
77 118 240 217 50 180 240 240 240 240 240 240 240 240 240 240
|
||||
175 153 163 186 53 226 240 240 240 240 240 240 240 240 240 240
|
||||
209 155 72 85 216 240 240 240 240 240 240 240 240 240 239 233
|
@ -1,15 +1,29 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import 'papercss/dist/paper.min.css';
|
||||
import { onMount } from 'svelte';
|
||||
import { Router, Route } from 'svelte-navigator';
|
||||
|
||||
import Test3D from './pages/test3D.svelte';
|
||||
import { currentUser } from './store/user';
|
||||
import { read } from './functions/user';
|
||||
import ViewAR from './pages/ViewAR.svelte';
|
||||
import Login from './pages/Login.svelte';
|
||||
import Profile from './pages/Profile.svelte';
|
||||
|
||||
onMount(async () => {
|
||||
if ($currentUser) {
|
||||
try {
|
||||
const user = await read($currentUser.uuid);
|
||||
currentUser.set(user);
|
||||
} catch (error) {
|
||||
currentUser.set(null);
|
||||
window.location.href = '/';
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<Router>
|
||||
<Route path="/">
|
||||
<Test3D />
|
||||
<ViewAR />
|
||||
</Route>
|
||||
<Route path="/login">
|
||||
<Login />
|
||||
|
@ -1,16 +1,13 @@
|
||||
<script lang="ts">
|
||||
import NavBar from '../components/NavBar.svelte';
|
||||
import { beforeUpdate, afterUpdate, onMount, onDestroy } from 'svelte';
|
||||
import * as Three from 'three';
|
||||
|
||||
let container: HTMLElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let width: number;
|
||||
let height: number;
|
||||
export let width: number;
|
||||
export let height: number;
|
||||
|
||||
//#region variables
|
||||
//let innerWidth: number = 0;
|
||||
//let innerHeight: number = 0;
|
||||
let container: HTMLElement;
|
||||
let canvas: HTMLCanvasElement;
|
||||
let maxInnerWidth: number = 0;
|
||||
let maxInnerHeight: number = 0;
|
||||
|
||||
@ -18,6 +15,21 @@
|
||||
let focalLength: number = 540 / Math.atan((70 * Math.PI) / 180);
|
||||
let fov = 75;
|
||||
//let baseHorizontalFOV: number = 2.0*Math.atan(baseAspectRation*Math.tan(baseVerticalFOV*0.5));
|
||||
|
||||
let scene: Three.Scene = new Three.Scene();
|
||||
let camera: Three.PerspectiveCamera = new Three.PerspectiveCamera(
|
||||
75,
|
||||
1,
|
||||
0.1,
|
||||
1000,
|
||||
);
|
||||
|
||||
let renderer: Three.WebGLRenderer = new Three.WebGLRenderer();
|
||||
let box: Three.BoxGeometry = new Three.BoxGeometry(1, 1, 1);
|
||||
let mat: Three.MeshBasicMaterial = new Three.MeshBasicMaterial({
|
||||
color: 0x00ff00,
|
||||
});
|
||||
let cube = new Three.Mesh(box, mat);
|
||||
//#endregion
|
||||
|
||||
//#region functions
|
||||
@ -50,22 +62,6 @@
|
||||
resetMaxDimensions();
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
let scene: Three.Scene = new Three.Scene();
|
||||
let camera: Three.PerspectiveCamera = new Three.PerspectiveCamera(
|
||||
75,
|
||||
1,
|
||||
0.1,
|
||||
1000,
|
||||
);
|
||||
|
||||
let renderer: Three.WebGLRenderer = new Three.WebGLRenderer();
|
||||
let box: Three.BoxGeometry = new Three.BoxGeometry(1, 1, 1);
|
||||
let mat: Three.MeshBasicMaterial = new Three.MeshBasicMaterial({
|
||||
color: 0x00ff00,
|
||||
});
|
||||
let cube = new Three.Mesh(box, mat);
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
@ -75,6 +71,7 @@
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
onMount(() => {
|
||||
canvas = container.appendChild(renderer.domElement);
|
||||
@ -96,7 +93,7 @@
|
||||
camera.setViewOffset(width, height, 0, 0, width, height);
|
||||
renderer.setSize(width, height);
|
||||
|
||||
//renderer.setClearColor(0x000000, (innerHeight/(maxInnerHeight))/2 + 0.5);
|
||||
renderer.setClearColor(0x000000, 0.1);
|
||||
});
|
||||
|
||||
afterUpdate(() => {});
|
||||
@ -106,17 +103,15 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
id="container"
|
||||
bind:this={container}
|
||||
bind:clientWidth={width}
|
||||
bind:clientHeight={height}
|
||||
/>
|
||||
<NavBar />
|
||||
<div class="Container" bind:this={container} />
|
||||
|
||||
<!--<svelte:window bind:innerWidth bind:innerHeight /> -->
|
||||
<style>
|
||||
#container {
|
||||
.Container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
24
www/src/components/ARHandler.svelte
Normal file
24
www/src/components/ARHandler.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script context="module">
|
||||
import 'aframe';
|
||||
import '@ar-js-org/ar.js/aframe/build/aframe-ar';
|
||||
</script>
|
||||
|
||||
<!--
|
||||
<script>
|
||||
let Angle = 45;
|
||||
setInterval(() => {
|
||||
Angle++;
|
||||
}, 100);
|
||||
</script>
|
||||
-->
|
||||
|
||||
<a-scene embedded arjs>
|
||||
<a-marker preset="hiro">
|
||||
<a-entity
|
||||
position="0 0 0"
|
||||
scale="0.10 0.10 0.10"
|
||||
gltf-model="/models/dingus_the_cat.glb"
|
||||
/>
|
||||
</a-marker>
|
||||
<a-entity camera />
|
||||
</a-scene>
|
45
www/src/components/CameraHandler.svelte
Normal file
45
www/src/components/CameraHandler.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import CameraPreview from './CameraPreview.svelte';
|
||||
import { getMediaStream, getImageCapture } from '../helpers/mediaHelper';
|
||||
|
||||
export let width: number;
|
||||
export let height: number;
|
||||
|
||||
let container: HTMLElement;
|
||||
|
||||
let cameraWidth: number = 0;
|
||||
let cameraHeight: number = 0;
|
||||
|
||||
let pictureUrl: string;
|
||||
let imageCapture: ImageCapture;
|
||||
let mediaStreamPromise: Promise<MediaStream>;
|
||||
|
||||
onMount(() => {
|
||||
mediaStreamPromise = getMediaStream({ video: true }).then((mediaStream) => {
|
||||
imageCapture = getImageCapture(mediaStream);
|
||||
return mediaStream;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="Container">
|
||||
{#await mediaStreamPromise}
|
||||
<h1>Waiting for camera....</h1>
|
||||
{:then mediaStream}
|
||||
<CameraPreview {mediaStream} {height} {width} />
|
||||
{:catch error}
|
||||
<h1>Error: {error.message}</h1>
|
||||
{/await}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.Container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
24
www/src/components/CameraPreview.svelte
Normal file
24
www/src/components/CameraPreview.svelte
Normal file
@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let mediaStream: MediaStream;
|
||||
export let width: number;
|
||||
export let height: number;
|
||||
|
||||
function srcObject(node, stream) {
|
||||
node.srcObject = stream;
|
||||
return {
|
||||
update(newStream) {
|
||||
if (node.srcObject != newStream) {
|
||||
node.srcObject = newStream;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<video
|
||||
use:srcObject={mediaStream}
|
||||
width={width}
|
||||
height={height}
|
||||
autoplay
|
||||
playsinline
|
||||
/>
|
@ -4,18 +4,15 @@ enum Methods {
|
||||
'PUT' = 'PUT',
|
||||
}
|
||||
|
||||
export async function get<T>(route: string): Promise<T | null> {
|
||||
export async function get<T>(route: string): Promise<T> {
|
||||
return request<T>('GET', route);
|
||||
}
|
||||
|
||||
export async function post<T>(
|
||||
route: string,
|
||||
data?: unknown,
|
||||
): Promise<T | null> {
|
||||
export async function post<T>(route: string, data?: unknown): Promise<T> {
|
||||
return request<T>('POST', route, data);
|
||||
}
|
||||
|
||||
export async function put<T>(route: string, data: unknown): Promise<T | null> {
|
||||
export async function put<T>(route: string, data: unknown): Promise<T> {
|
||||
return request<T>('PUT', route, data);
|
||||
}
|
||||
|
||||
@ -23,7 +20,7 @@ async function request<T>(
|
||||
method: keyof typeof Methods,
|
||||
route: string,
|
||||
data?: unknown,
|
||||
): Promise<T | null> {
|
||||
): Promise<T> {
|
||||
const response = await fetch(`${process.env.APIURL}${route}`, {
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
@ -34,8 +31,11 @@ async function request<T>(
|
||||
body: data ? JSON.stringify(data) : null,
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(await response.json());
|
||||
|
||||
if (response.ok && response.status !== 204) {
|
||||
return response.json() as T;
|
||||
}
|
||||
return null;
|
||||
|
||||
return {} as T;
|
||||
}
|
||||
|
@ -1,22 +1,18 @@
|
||||
import type { CreateUserBody, LoginUserBody, UserInfo } from '@core';
|
||||
import { post, get } from './request';
|
||||
import { currentUser } from '../store/user';
|
||||
|
||||
export async function login(raw: LoginUserBody) {
|
||||
const user = await post<UserInfo>('/user/login', raw);
|
||||
currentUser.set(user);
|
||||
return user;
|
||||
return post<UserInfo>('/user/login', raw);
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
await post('/user/logout');
|
||||
currentUser.set(null);
|
||||
await post<void>('/user/logout');
|
||||
}
|
||||
|
||||
export async function read(uuid: string) {
|
||||
const user = await get<UserInfo>(`/user/read/${uuid}`);
|
||||
return get<UserInfo>(`/user/read/${uuid}`);
|
||||
}
|
||||
|
||||
export async function create(raw: CreateUserBody) {
|
||||
const user = await post<UserInfo>('/user/create', raw);
|
||||
return post<UserInfo>('/user/create', raw);
|
||||
}
|
||||
|
10
www/src/helpers/mediaHelper.ts
Normal file
10
www/src/helpers/mediaHelper.ts
Normal file
@ -0,0 +1,10 @@
|
||||
function getMediaStream(constraints = { video: true }) {
|
||||
return navigator.mediaDevices.getUserMedia(constraints);
|
||||
}
|
||||
|
||||
function getImageCapture(mediaStream) {
|
||||
const track = mediaStream.getVideoTracks()[0];
|
||||
return new ImageCapture(track);
|
||||
}
|
||||
|
||||
export { getMediaStream, getImageCapture };
|
@ -3,6 +3,7 @@
|
||||
import NavBar from '../components/NavBar.svelte';
|
||||
import { Form, Input, Button } from 'spaper';
|
||||
import { login } from '../functions/user';
|
||||
import { currentUser } from '../store/user';
|
||||
import { useNavigate } from 'svelte-navigator';
|
||||
|
||||
const user: LoginUserBody = {
|
||||
@ -13,10 +14,11 @@
|
||||
const navigate = useNavigate();
|
||||
|
||||
const loginHandler = async () => {
|
||||
const result = await login(user);
|
||||
if (result) {
|
||||
try {
|
||||
const res = await login(user);
|
||||
currentUser.set(res);
|
||||
navigate('/');
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -39,7 +41,7 @@
|
||||
type="secondary"
|
||||
class="row sm-2 col-4"
|
||||
block
|
||||
on:click={() => loginHandler()}>Sign in</Button
|
||||
on:click={loginHandler}>Sign in</Button
|
||||
>
|
||||
</Form>
|
||||
</div>
|
||||
|
@ -8,12 +8,16 @@
|
||||
const navigate = useNavigate();
|
||||
|
||||
const logoutHandler = async () => {
|
||||
await logout();
|
||||
navigate('/');
|
||||
try {
|
||||
await logout();
|
||||
} finally {
|
||||
currentUser.set(null);
|
||||
navigate('/');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<Button type="danger" block on:click={() => logoutHandler()}>Logout</Button>
|
||||
<Button type="danger" block on:click={logoutHandler}>Logout</Button>
|
||||
{$currentUser?.uuid}
|
||||
{$currentUser?.username}
|
||||
{$currentUser?.role}
|
||||
|
26
www/src/pages/ViewAR.svelte
Normal file
26
www/src/pages/ViewAR.svelte
Normal file
@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import ARHandler from '../components/ARHandler.svelte';
|
||||
import NavBar from '../components/NavBar.svelte';
|
||||
|
||||
let containerHeight: number;
|
||||
let containerWidth: number;
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="viewAR"
|
||||
bind:clientHeight={containerHeight}
|
||||
bind:clientWidth={containerWidth}
|
||||
>
|
||||
<ARHandler/>
|
||||
<!-- <Camera height={containerHeight} width={containerWidth} /> -->
|
||||
<!-- <View3D height={containerHeight} width={containerWidth} /> -->
|
||||
</div>
|
||||
<NavBar />
|
||||
|
||||
<style>
|
||||
.viewAR {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -5,7 +5,8 @@
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"@core": ["../../core/src"]
|
||||
}
|
||||
},
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules/*", "public/*"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user