Compare commits
9 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
9df12a8a3c | 10 months ago |
|
|
c29f90ba73 | 10 months ago |
|
|
59f21ebf34 | 10 months ago |
|
|
9d5100e066 | 10 months ago |
|
|
efd47f2a89 | 10 months ago |
|
|
8a86733d5c | 10 months ago |
|
|
069af4cd09 | 10 months ago |
|
|
a8172f7e66 | 10 months ago |
|
|
a02801c0c8 | 11 months ago |
@ -0,0 +1,4 @@
|
|||||||
|
Dockerfile
|
||||||
|
node_modules
|
||||||
|
.git
|
||||||
|
*.local*
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
DB_FILE_NAME=file:data.local/database.db
|
||||||
|
BETTER_AUTH_SECRET=
|
||||||
|
BETTER_AUTH_URL=http://localhost:3000
|
||||||
|
OAUTH_CLIENT_ID=
|
||||||
|
OAUTH_CLIENT_SECRET=
|
||||||
|
OAUTH_AUTH_URL=https://iam.unipi.it/oauth2/authorize
|
||||||
|
OAUTH_TOKEN_HOST=https://iam.unipi.it
|
||||||
|
OAUTH_TOKEN_PATH=/oauth2/token
|
||||||
|
OAUTH_REDIRECT_URL=https://phc.dm.unipi.it/api/auth/oauth2/callback/unipi
|
||||||
|
OAUTH_USER_INFO_URL=https://iam.unipi.it/oauth2/userinfo
|
||||||
|
OAUTH_SCOPES="openid profile email"
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
# https://dev.to/code42cate/how-to-dockerize-and-deploy-astro-6ll
|
||||||
|
|
||||||
|
# use the official Bun image
|
||||||
|
# see all versions at https://hub.docker.com/r/oven/bun/tags
|
||||||
|
FROM oven/bun:1-alpine AS base
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
build-base \
|
||||||
|
python3
|
||||||
|
|
||||||
|
# install dependencies into temp directory to cache them and speed up future builds
|
||||||
|
FROM base AS install
|
||||||
|
RUN mkdir -p /temp/dev
|
||||||
|
COPY package.json bun.lockb /temp/dev/
|
||||||
|
RUN cd /temp/dev && bun install --frozen-lockfile
|
||||||
|
RUN mkdir -p /temp/prod
|
||||||
|
COPY package.json bun.lockb /temp/prod/
|
||||||
|
RUN cd /temp/prod && bun install --frozen-lockfile --production
|
||||||
|
|
||||||
|
# copy node_modules from temp directory and copy (non-ignored) project files into the image
|
||||||
|
FROM base AS prerelease
|
||||||
|
COPY --from=install /temp/dev/node_modules node_modules
|
||||||
|
COPY . .
|
||||||
|
RUN bun run build
|
||||||
|
|
||||||
|
# copy production dependencies and source code into final image
|
||||||
|
FROM base AS release
|
||||||
|
COPY --from=install /temp/prod/node_modules node_modules
|
||||||
|
COPY --from=prerelease /app .
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
ENV PORT=3000
|
||||||
|
EXPOSE 3000/tcp
|
||||||
|
CMD bun run start
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
services:
|
||||||
|
website:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
container_name: website
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
# https://gist.github.com/aziis98/88af12b32d9cf3eeae3929b93146fd27
|
||||||
|
# hash2addr "next.phc.dm.unipi.it"
|
||||||
|
- "127.44.207.62:1059:3000"
|
||||||
|
volumes:
|
||||||
|
- /var/lib/website:/app/data.local
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import 'dotenv/config'
|
||||||
|
import { defineConfig } from 'drizzle-kit'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
out: './drizzle',
|
||||||
|
schema: './src/db/schema.ts',
|
||||||
|
dialect: 'sqlite',
|
||||||
|
dbCredentials: {
|
||||||
|
url: process.env.DB_FILE_NAME!,
|
||||||
|
},
|
||||||
|
})
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
CREATE TABLE `accounts` (
|
||||||
|
`user_id` text,
|
||||||
|
`provider` text NOT NULL,
|
||||||
|
`username` text NOT NULL,
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `appunti` (
|
||||||
|
`user_id` text,
|
||||||
|
`hash` text NOT NULL,
|
||||||
|
`link` text,
|
||||||
|
`visibility` text NOT NULL,
|
||||||
|
`title` text NOT NULL,
|
||||||
|
`description` text,
|
||||||
|
`tags` text NOT NULL,
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `poisson_requests` (
|
||||||
|
`user_id` text,
|
||||||
|
`request_type` text NOT NULL,
|
||||||
|
`comments` text,
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`id` text,
|
||||||
|
`username` text NOT NULL,
|
||||||
|
`full_name` text,
|
||||||
|
`email` text,
|
||||||
|
FOREIGN KEY (`id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `account` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`account_id` text NOT NULL,
|
||||||
|
`provider_id` text NOT NULL,
|
||||||
|
`user_id` text NOT NULL,
|
||||||
|
`access_token` text,
|
||||||
|
`refresh_token` text,
|
||||||
|
`id_token` text,
|
||||||
|
`access_token_expires_at` integer,
|
||||||
|
`refresh_token_expires_at` integer,
|
||||||
|
`scope` text,
|
||||||
|
`password` text,
|
||||||
|
`created_at` integer NOT NULL,
|
||||||
|
`updated_at` integer NOT NULL,
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE `session` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`expires_at` integer NOT NULL,
|
||||||
|
`token` text NOT NULL,
|
||||||
|
`created_at` integer NOT NULL,
|
||||||
|
`updated_at` integer NOT NULL,
|
||||||
|
`ip_address` text,
|
||||||
|
`user_agent` text,
|
||||||
|
`user_id` text NOT NULL,
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `session_token_unique` ON `session` (`token`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `user` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`name` text NOT NULL,
|
||||||
|
`email` text NOT NULL,
|
||||||
|
`email_verified` integer NOT NULL,
|
||||||
|
`image` text,
|
||||||
|
`created_at` integer NOT NULL,
|
||||||
|
`updated_at` integer NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);--> statement-breakpoint
|
||||||
|
CREATE TABLE `verification` (
|
||||||
|
`id` text PRIMARY KEY NOT NULL,
|
||||||
|
`identifier` text NOT NULL,
|
||||||
|
`value` text NOT NULL,
|
||||||
|
`expires_at` integer NOT NULL,
|
||||||
|
`created_at` integer,
|
||||||
|
`updated_at` integer
|
||||||
|
);
|
||||||
@ -0,0 +1,555 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "84352768-6c24-4412-9d9e-8a3c756d31b1",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"tables": {
|
||||||
|
"accounts": {
|
||||||
|
"name": "accounts",
|
||||||
|
"columns": {
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"provider": {
|
||||||
|
"name": "provider",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"accounts_user_id_user_id_fk": {
|
||||||
|
"name": "accounts_user_id_user_id_fk",
|
||||||
|
"tableFrom": "accounts",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"appunti": {
|
||||||
|
"name": "appunti",
|
||||||
|
"columns": {
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"hash": {
|
||||||
|
"name": "hash",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"link": {
|
||||||
|
"name": "link",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"name": "visibility",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"name": "tags",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"appunti_user_id_users_id_fk": {
|
||||||
|
"name": "appunti_user_id_users_id_fk",
|
||||||
|
"tableFrom": "appunti",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"poisson_requests": {
|
||||||
|
"name": "poisson_requests",
|
||||||
|
"columns": {
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"request_type": {
|
||||||
|
"name": "request_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"comments": {
|
||||||
|
"name": "comments",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"poisson_requests_user_id_users_id_fk": {
|
||||||
|
"name": "poisson_requests_user_id_users_id_fk",
|
||||||
|
"tableFrom": "poisson_requests",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"name": "users",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"full_name": {
|
||||||
|
"name": "full_name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"users_id_user_id_fk": {
|
||||||
|
"name": "users_id_user_id_fk",
|
||||||
|
"tableFrom": "users",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"name": "account",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"account_id": {
|
||||||
|
"name": "account_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"provider_id": {
|
||||||
|
"name": "provider_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"access_token": {
|
||||||
|
"name": "access_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"name": "refresh_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"id_token": {
|
||||||
|
"name": "id_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"access_token_expires_at": {
|
||||||
|
"name": "access_token_expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"refresh_token_expires_at": {
|
||||||
|
"name": "refresh_token_expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"name": "scope",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"name": "password",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"account_user_id_user_id_fk": {
|
||||||
|
"name": "account_user_id_user_id_fk",
|
||||||
|
"tableFrom": "account",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"name": "session",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"name": "token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"ip_address": {
|
||||||
|
"name": "ip_address",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"user_agent": {
|
||||||
|
"name": "user_agent",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"session_token_unique": {
|
||||||
|
"name": "session_token_unique",
|
||||||
|
"columns": [
|
||||||
|
"token"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"session_user_id_user_id_fk": {
|
||||||
|
"name": "session_user_id_user_id_fk",
|
||||||
|
"tableFrom": "session",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"name": "user",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"email_verified": {
|
||||||
|
"name": "email_verified",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"name": "image",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email_unique": {
|
||||||
|
"name": "user_email_unique",
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"verification": {
|
||||||
|
"name": "verification",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"identifier": {
|
||||||
|
"name": "identifier",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1749233567397,
|
||||||
|
"tag": "0000_violet_agent_zero",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { betterAuth } from 'better-auth'
|
||||||
|
import { genericOAuth } from 'better-auth/plugins'
|
||||||
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
||||||
|
import * as authSchema from '@/db/auth-schema'
|
||||||
|
import db from '@/db'
|
||||||
|
|
||||||
|
export const auth = betterAuth({
|
||||||
|
database: drizzleAdapter(db, {
|
||||||
|
provider: 'sqlite',
|
||||||
|
schema: authSchema,
|
||||||
|
}),
|
||||||
|
plugins: [
|
||||||
|
genericOAuth({
|
||||||
|
config: [
|
||||||
|
{
|
||||||
|
providerId: 'unipi',
|
||||||
|
clientId: process.env.OAUTH_CLIENT_ID!,
|
||||||
|
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
|
||||||
|
scopes: process.env.OAUTH_SCOPES!.split(' '),
|
||||||
|
userInfoUrl: process.env.OAUTH_USER_INFO_URL!,
|
||||||
|
authorizationUrl: process.env.OAUTH_AUTH_URL!,
|
||||||
|
tokenUrl: `${process.env.OAUTH_TOKEN_HOST}${process.env.OAUTH_TOKEN_PATH}`,
|
||||||
|
redirectURI: process.env.OAUTH_REDIRECT_URL!,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { createAuthClient } from 'better-auth/client'
|
||||||
|
import { genericOAuthClient } from 'better-auth/client/plugins'
|
||||||
|
export const authClient = createAuthClient({
|
||||||
|
plugins: [genericOAuthClient()],
|
||||||
|
})
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
|
||||||
|
|
||||||
|
export const user = sqliteTable('user', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
name: text('name').notNull(),
|
||||||
|
email: text('email').notNull().unique(),
|
||||||
|
emailVerified: integer('email_verified', { mode: 'boolean' })
|
||||||
|
.$defaultFn(() => false)
|
||||||
|
.notNull(),
|
||||||
|
image: text('image'),
|
||||||
|
createdAt: integer('created_at', { mode: 'timestamp' })
|
||||||
|
.$defaultFn(() => /* @__PURE__ */ new Date())
|
||||||
|
.notNull(),
|
||||||
|
updatedAt: integer('updated_at', { mode: 'timestamp' })
|
||||||
|
.$defaultFn(() => /* @__PURE__ */ new Date())
|
||||||
|
.notNull(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const session = sqliteTable('session', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
token: text('token').notNull().unique(),
|
||||||
|
createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
ipAddress: text('ip_address'),
|
||||||
|
userAgent: text('user_agent'),
|
||||||
|
userId: text('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id, { onDelete: 'cascade' }),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const account = sqliteTable('account', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
accountId: text('account_id').notNull(),
|
||||||
|
providerId: text('provider_id').notNull(),
|
||||||
|
userId: text('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => user.id, { onDelete: 'cascade' }),
|
||||||
|
accessToken: text('access_token'),
|
||||||
|
refreshToken: text('refresh_token'),
|
||||||
|
idToken: text('id_token'),
|
||||||
|
accessTokenExpiresAt: integer('access_token_expires_at', { mode: 'timestamp' }),
|
||||||
|
refreshTokenExpiresAt: integer('refresh_token_expires_at', { mode: 'timestamp' }),
|
||||||
|
scope: text('scope'),
|
||||||
|
password: text('password'),
|
||||||
|
createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const verification = sqliteTable('verification', {
|
||||||
|
id: text('id').primaryKey(),
|
||||||
|
identifier: text('identifier').notNull(),
|
||||||
|
value: text('value').notNull(),
|
||||||
|
expiresAt: integer('expires_at', { mode: 'timestamp' }).notNull(),
|
||||||
|
createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(() => /* @__PURE__ */ new Date()),
|
||||||
|
updatedAt: integer('updated_at', { mode: 'timestamp' }).$defaultFn(() => /* @__PURE__ */ new Date()),
|
||||||
|
})
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
import 'dotenv/config'
|
||||||
|
import { drizzle } from 'drizzle-orm/libsql'
|
||||||
|
|
||||||
|
export default drizzle(process.env.DB_FILE_NAME!)
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||||
|
export * from './auth-schema'
|
||||||
|
|
||||||
|
import { user } from './auth-schema'
|
||||||
|
|
||||||
|
export const usersTable = sqliteTable('users', {
|
||||||
|
id: text('id').references(() => user.id),
|
||||||
|
username: text('username').notNull(),
|
||||||
|
fullName: text('full_name'),
|
||||||
|
email: text('email'),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const accountsTable = sqliteTable('accounts', {
|
||||||
|
userId: text('user_id').references(() => user.id),
|
||||||
|
provider: text('provider').notNull(),
|
||||||
|
username: text('username').notNull(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const poissonRequestsTable = sqliteTable('poisson_requests', {
|
||||||
|
userId: text('user_id').references(() => usersTable.id),
|
||||||
|
requestType: text('request_type').notNull(), // "link" or "create"
|
||||||
|
comments: text('comments'), // contains username suggestions
|
||||||
|
})
|
||||||
|
|
||||||
|
export const appuntiTable = sqliteTable('appunti', {
|
||||||
|
userId: text('user_id').references(() => usersTable.id),
|
||||||
|
hash: text('hash').notNull(),
|
||||||
|
link: text('link'),
|
||||||
|
visibility: text('visibility').notNull(), // "public", "internal", "private"
|
||||||
|
title: text('title').notNull(),
|
||||||
|
description: text('description'),
|
||||||
|
tags: text('tags').notNull(), // Array of strings, e.g. ["#geometria-2", "#511aa", "#2017-18", "#frigerio"]
|
||||||
|
})
|
||||||
@ -1,2 +1,10 @@
|
|||||||
/// <reference path="../.astro/types.d.ts" />
|
/// <reference path="../.astro/types.d.ts" />
|
||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client" />
|
||||||
|
|
||||||
|
declare namespace App {
|
||||||
|
// Note: 'import {} from ""' syntax does not work in .d.ts files.
|
||||||
|
interface Locals {
|
||||||
|
user: import('better-auth').User | null
|
||||||
|
session: import('better-auth').Session | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { auth } from '@/auth'
|
||||||
|
import { defineMiddleware } from 'astro:middleware'
|
||||||
|
|
||||||
|
export const onRequest = defineMiddleware(async (context, next) => {
|
||||||
|
const isAuthed = await auth.api.getSession({
|
||||||
|
headers: context.request.headers,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isAuthed) {
|
||||||
|
context.locals.user = isAuthed.user
|
||||||
|
context.locals.session = isAuthed.session
|
||||||
|
} else {
|
||||||
|
context.locals.user = null
|
||||||
|
context.locals.session = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return next()
|
||||||
|
})
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { auth } from '@/auth'
|
||||||
|
import type { APIRoute } from 'astro'
|
||||||
|
|
||||||
|
export const ALL: APIRoute = async ctx => {
|
||||||
|
// If you want to use rate limiting, make sure to set the 'x-forwarded-for' header to the request headers from the context
|
||||||
|
// ctx.request.headers.set("x-forwarded-for", ctx.clientAddress);
|
||||||
|
return auth.handler(ctx.request)
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<script>
|
||||||
|
import { authClient } from '@/client/auth-client' //import the auth client
|
||||||
|
|
||||||
|
await authClient.signIn.oauth2({
|
||||||
|
providerId: 'unipi',
|
||||||
|
callbackURL: '/profilo', // the path to redirect to after the user is authenticated
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
import PageLayout from '../layouts/PageLayout.astro'
|
||||||
|
import '@/styles/pages/login.css'
|
||||||
|
|
||||||
|
if (!Astro.locals.user) {
|
||||||
|
return Astro.redirect('/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, email } = Astro.locals.user
|
||||||
|
---
|
||||||
|
|
||||||
|
<PageLayout title="Profilo | PHC">
|
||||||
|
<div class="card large">
|
||||||
|
<div class="title">Profilo di {name}</div>
|
||||||
|
<div class="text">
|
||||||
|
<p>
|
||||||
|
<strong>Nome:</strong>
|
||||||
|
{name}
|
||||||
|
<br />
|
||||||
|
<strong>Email:</strong>
|
||||||
|
{email}
|
||||||
|
<br />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Benvenuto nel tuo profilo! Qui puoi visualizzare le tue informazioni personali e modificare le tue
|
||||||
|
impostazioni.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="title">Impostazioni</div>
|
||||||
|
<div class="text">
|
||||||
|
<p>
|
||||||
|
Al momento non sono disponibili impostazioni modificabili. Se hai bisogno di assistenza, contatta il
|
||||||
|
supporto tecnico.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageLayout>
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/* This file is here for historical reasons but is not used anymore */
|
|
||||||
|
|
||||||
@layer page {
|
|
||||||
/*
|
|
||||||
.login {
|
|
||||||
background: #ddfaff;
|
|
||||||
|
|
||||||
main {
|
|
||||||
justify-self: center;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
max-width: 80ch;
|
|
||||||
padding: 3rem 0;
|
|
||||||
|
|
||||||
gap: 3rem;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
@layer page {
|
||||||
|
main {
|
||||||
|
justify-self: center;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
place-content: center;
|
||||||
|
|
||||||
|
padding: 4.5rem 3rem;
|
||||||
|
gap: 4.5rem;
|
||||||
|
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
padding: 3rem 1.5rem;
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue