Compare commits
4 commits
master
...
wip-gitea-
Author | SHA1 | Date | |
---|---|---|---|
968a799b35 | |||
3f79ff8cb4 | |||
5d0fcf7551 | |||
605fced22d |
14 changed files with 686 additions and 565 deletions
6
migrations/20221215163426_librepages_gitea.sql
Normal file
6
migrations/20221215163426_librepages_gitea.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS librepages_gitea_instances (
|
||||||
|
url VARCHAR(3000) NOT NULL UNIQUE,
|
||||||
|
client_id TEXT NOT NULL,
|
||||||
|
client_secret TEXT NOT NULL,
|
||||||
|
ID SERIAL PRIMARY KEY NOT NULL
|
||||||
|
);
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- Add migration script here
|
||||||
|
CREATE TABLE IF NOT EXISTS librepages_gitea_oidc_configuration (
|
||||||
|
gitea_instance INTEGER NOT NULL references librepages_gitea_instances(ID) ON DELETE CASCADE,
|
||||||
|
authorization_endpoint VARCHAR(3000) NOT NULL UNIQUE,
|
||||||
|
token_endpoint VARCHAR(3000) NOT NULL UNIQUE,
|
||||||
|
userinfo_endpoint VARCHAR(3000) NOT NULL UNIQUE,
|
||||||
|
introspection_endpoint VARCHAR(3000) NOT NULL UNIQUE,
|
||||||
|
ID SERIAL PRIMARY KEY NOT NULL
|
||||||
|
)
|
566
sqlx-data.json
566
sqlx-data.json
|
@ -1,567 +1,3 @@
|
||||||
{
|
{
|
||||||
"db": "PostgreSQL",
|
"db": "PostgreSQL"
|
||||||
"10d30dade86d79210203bdbce4b6db5d2aa446b0f88ca834771ecbbe11be51fb": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "UPDATE librepages_sites SET deleted = true\n WHERE hostname = ($1)\n AND owned_by = ( SELECT ID FROM librepages_users WHERE name = $2);\n "
|
|
||||||
},
|
|
||||||
"12391b10cf16a807322c49c9cc7e0a015f26b445beacf4cdd4e7714f36b4adf6": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "site_secret",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "repo_url",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "branch",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hostname",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT site_secret, repo_url, branch, hostname, pub_id\n FROM librepages_sites\n WHERE deleted = false\n AND owned_by = (SELECT ID FROM librepages_users WHERE name = $1 );\n "
|
|
||||||
},
|
|
||||||
"14cdc724af64942e93994f97e9eafc8272d15605eff7aab9e5177d01f2bf6118": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Timestamptz",
|
|
||||||
"Text",
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "INSERT INTO librepages_site_deploy_events\n (event_type, time, site, pub_id) VALUES (\n (SELECT iD from librepages_deploy_event_type WHERE name = $1),\n $2,\n (SELECT ID from librepages_sites WHERE hostname = $3),\n $4\n );\n "
|
|
||||||
},
|
|
||||||
"1be33ea4fe0e6079c88768ff912b824f4b0250193f2d086046c1fd0da125ae0c": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "password",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT name, password FROM librepages_users WHERE name = ($1)"
|
|
||||||
},
|
|
||||||
"279b5ae27935279b06d2799eef2da6a316324a05d23ba7a729c608c70168c496": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "UPDATE librepages_users set name = $1\n WHERE name = $2"
|
|
||||||
},
|
|
||||||
"39854fcbfb0247377c6c5ca70c2c0fa7804548848bf56f881eea2f8242e7a09d": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "time",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Timestamptz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT\n librepages_deploy_event_type.name,\n librepages_site_deploy_events.time,\n librepages_site_deploy_events.pub_id\n FROM\n librepages_site_deploy_events\n INNER JOIN librepages_deploy_event_type ON\n librepages_deploy_event_type.ID = librepages_site_deploy_events.event_type\n WHERE\n librepages_site_deploy_events.site = (\n SELECT ID FROM librepages_sites WHERE hostname = $1\n )\n AND\n librepages_site_deploy_events.pub_id = $2\n "
|
|
||||||
},
|
|
||||||
"432fe829719ce8110f768b4a611724bb34191ac224d2143ff4c81548da75c103": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "repo_url",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "branch",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hostname",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "owned_by",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "site_secret",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT repo_url, branch, hostname, owned_by, site_secret\n FROM librepages_sites\n WHERE pub_id = $1\n AND\n owned_by = (SELECT ID from librepages_users WHERE name = $2)\n AND\n deleted = false;\n "
|
|
||||||
},
|
|
||||||
"53f3c21c06c8d1c218537dfa9183fd0604aaf28200d8aa12e97db4ac317df39e": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT name FROM librepages_users WHERE ID = $1"
|
|
||||||
},
|
|
||||||
"54f1ad328c83997d5e80686665d4cfef58d3529d24cb6caaa7ff301479e5d735": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "repo_url",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "branch",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hostname",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "owned_by",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Int4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT repo_url, branch, hostname, owned_by, pub_id\n FROM librepages_sites\n WHERE site_secret = $1\n AND deleted = false;\n "
|
|
||||||
},
|
|
||||||
"5c5d774bde06c0ab83c3616a56a28f12dfd9c546cbaac9f246d3b350c587823e": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "DELETE FROM librepages_users WHERE name = ($1)"
|
|
||||||
},
|
|
||||||
"65f6181364cd8c6ed4eae3f62b5ae771a27e8da6e698c235ca77d4cec784d04b": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "site_secret",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "repo_url",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "branch",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "hostname",
|
|
||||||
"ordinal": 3,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT site_secret, repo_url, branch, hostname, pub_id\n FROM librepages_sites\n WHERE deleted = false\n AND owned_by = (SELECT ID FROM librepages_users WHERE name = $1 )\n AND hostname = $2;\n "
|
|
||||||
},
|
|
||||||
"6a557f851d4f47383b864085093beb0954e79779f21b655978f07e285281e0ac": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "UPDATE librepages_users set email = $1\n WHERE name = $2"
|
|
||||||
},
|
|
||||||
"6db98c6ae90b8eb98ace1a5acfa3c8af2b6ed7d51c6debda12637f5d7b076c15": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT EXISTS (SELECT 1 from librepages_sites WHERE hostname = $1 AND deleted = false)"
|
|
||||||
},
|
|
||||||
"77612c85be99e6de2e4a6e3105ebaeb470d6cc57b2999b673a085da41c035f9e": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "time",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Timestamptz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT\n time,\n pub_id\n FROM\n librepages_site_deploy_events\n WHERE\n site = (SELECT ID FROM librepages_sites WHERE hostname = $1)\n AND\n event_type = (SELECT ID FROM librepages_deploy_event_type WHERE name = $2)\n AND\n time = (\n SELECT MAX(time) \n FROM\n librepages_site_deploy_events\n WHERE\n site = (SELECT ID FROM librepages_sites WHERE hostname = $1)\n )\n "
|
|
||||||
},
|
|
||||||
"8735b654bc261571e6a5908d55a8217474c76bdff7f3cbcc71500a0fe13249db": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT EXISTS (SELECT 1 from librepages_users WHERE email = $1)"
|
|
||||||
},
|
|
||||||
"924e756de5544cece865a10a7e136ecc6126e3a603947264cc7899387c18c819": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "UPDATE librepages_users set password = $1\n WHERE name = $2"
|
|
||||||
},
|
|
||||||
"b48c77db6e663d97df44bf9ec2ee92fd3e02f2dcbcdbd1d491e09fab2da68494": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "password",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Text"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT name, password FROM librepages_users WHERE email = ($1)"
|
|
||||||
},
|
|
||||||
"b8b1b3c5fa205b071f577b2ce9993ddfc7c99ada26aea48aa1c201c8c3c7fcf6": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar",
|
|
||||||
"Varchar",
|
|
||||||
"Text",
|
|
||||||
"Varchar",
|
|
||||||
"Uuid",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n INSERT INTO librepages_sites\n (site_secret, repo_url, branch, hostname, pub_id, owned_by)\n VALUES ($1, $2, $3, $4, $5, ( SELECT ID FROM librepages_users WHERE name = $6 ));\n "
|
|
||||||
},
|
|
||||||
"bdd4d2a1b0b97ebf8ed61cfd120b40146fbf3ea9afb5cd0e03c9d29860b6a26b": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT EXISTS (SELECT 1 from librepages_users WHERE name = $1)"
|
|
||||||
},
|
|
||||||
"ced69a08729ffb906e8971dbdce6a8d4197bc9bb8ccd7c58b3a88eb7be73fc2e": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "email",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT email FROM librepages_users WHERE name = $1"
|
|
||||||
},
|
|
||||||
"d2327c1bcb40e18518c2112413a19a9b26eb0f54f83c53e968c9752d70c8dd4e": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "name",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Varchar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "time",
|
|
||||||
"ordinal": 1,
|
|
||||||
"type_info": "Timestamptz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "pub_id",
|
|
||||||
"ordinal": 2,
|
|
||||||
"type_info": "Uuid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT\n librepages_deploy_event_type.name,\n librepages_site_deploy_events.time,\n librepages_site_deploy_events.pub_id\n FROM\n librepages_site_deploy_events\n INNER JOIN librepages_deploy_event_type ON\n librepages_deploy_event_type.ID = librepages_site_deploy_events.event_type\n WHERE\n librepages_site_deploy_events.site = (\n SELECT ID FROM librepages_sites WHERE hostname = $1\n );\n "
|
|
||||||
},
|
|
||||||
"e4adf1bc9175eeb9d61b495653bb452039cc38818c8792acdc6a1c732b6f4554": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "SELECT EXISTS (SELECT 1 from librepages_deploy_event_type WHERE name = $1)"
|
|
||||||
},
|
|
||||||
"f651da8f411b7977cb87dd8d4bd5d167661d7ef1d865747e76219453d386d593": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "INSERT INTO librepages_deploy_event_type\n (name) VALUES ($1) ON CONFLICT (name) DO NOTHING;"
|
|
||||||
},
|
|
||||||
"faa4170a309f19a4abf1ca3f8dd3c0526945aa00f028ebf8bd7063825d448f5b": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Varchar",
|
|
||||||
"Text",
|
|
||||||
"Varchar"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "INSERT INTO librepages_users\n (name , password, email) VALUES ($1, $2, $3)"
|
|
||||||
}
|
|
||||||
}
|
}
|
51
src/ctx/gitea.rs
Normal file
51
src/ctx/gitea.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::ctx::Ctx;
|
||||||
|
use crate::db::AddGiteaInstance;
|
||||||
|
use crate::errors::ServiceResult;
|
||||||
|
|
||||||
|
impl Ctx {
|
||||||
|
pub async fn init_gitea_instance(&self, info: &AddGiteaInstance) -> ServiceResult<()> {
|
||||||
|
let mut url = info.url.clone();
|
||||||
|
url.set_path("/.well-known/openid-configuration");
|
||||||
|
let res: OIDCConfiguration = self
|
||||||
|
.client
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
self.db.new_gitea_instance(&info).await?;
|
||||||
|
self.db
|
||||||
|
.new_gitea_oidc_configuration(&info.url, &res)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct OIDCConfiguration {
|
||||||
|
pub authorization_endpoint: Url,
|
||||||
|
pub token_endpoint: Url,
|
||||||
|
pub userinfo_endpoint: Url,
|
||||||
|
pub introspection_endpoint: Url,
|
||||||
|
}
|
|
@ -20,9 +20,11 @@ use std::thread;
|
||||||
use crate::db::*;
|
use crate::db::*;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use argon2_creds::{Config as ArgonConfig, ConfigBuilder as ArgonConfigBuilder, PasswordPolicy};
|
use argon2_creds::{Config as ArgonConfig, ConfigBuilder as ArgonConfigBuilder, PasswordPolicy};
|
||||||
|
use reqwest::Client;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod gitea;
|
||||||
|
|
||||||
use crate::conductor::Conductor;
|
use crate::conductor::Conductor;
|
||||||
|
|
||||||
|
@ -35,6 +37,7 @@ pub struct Ctx {
|
||||||
pub conductor: Conductor,
|
pub conductor: Conductor,
|
||||||
/// credential-procession policy
|
/// credential-procession policy
|
||||||
pub creds: ArgonConfig,
|
pub creds: ArgonConfig,
|
||||||
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
|
@ -65,11 +68,13 @@ impl Ctx {
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
init.join();
|
init.join();
|
||||||
|
|
||||||
|
let client = Client::new();
|
||||||
Arc::new(Self {
|
Arc::new(Self {
|
||||||
settings,
|
settings,
|
||||||
db,
|
db,
|
||||||
creds,
|
creds,
|
||||||
conductor,
|
conductor,
|
||||||
|
client,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
185
src/db.rs
185
src/db.rs
|
@ -23,8 +23,10 @@ use sqlx::types::time::OffsetDateTime;
|
||||||
use sqlx::ConnectOptions;
|
use sqlx::ConnectOptions;
|
||||||
use sqlx::PgPool;
|
use sqlx::PgPool;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::ctx::gitea::OIDCConfiguration;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
/// Connect to databse
|
/// Connect to databse
|
||||||
|
@ -621,6 +623,103 @@ impl Database {
|
||||||
}
|
}
|
||||||
Ok(events)
|
Ok(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn new_gitea_instance(&self, payload: &AddGiteaInstance) -> ServiceResult<()> {
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO librepages_gitea_instances
|
||||||
|
(url , client_id, client_secret) VALUES ($1, $2, $3)",
|
||||||
|
&payload.url.as_str(),
|
||||||
|
payload.client_id,
|
||||||
|
payload.client_secret,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(map_register_err)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_gitea_instance(&self, url: &Url) -> ServiceResult<()> {
|
||||||
|
sqlx::query!(
|
||||||
|
"DELETE FROM librepages_gitea_instances WHERE url = ($1)",
|
||||||
|
url.as_str()
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(map_register_err)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_gitea_password(&self, url: &Url) -> ServiceResult<GiteaInstance> {
|
||||||
|
let res = sqlx::query_as!(
|
||||||
|
GiteaInstance,
|
||||||
|
"SELECT client_id, client_secret FROM librepages_gitea_instances WHERE url = ($1)",
|
||||||
|
url.as_str()
|
||||||
|
)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, ServiceError::GiteaInstanceNotFound))?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn new_gitea_oidc_configuration(
|
||||||
|
&self,
|
||||||
|
url: &Url,
|
||||||
|
payload: &OIDCConfiguration,
|
||||||
|
) -> ServiceResult<()> {
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO librepages_gitea_oidc_configuration
|
||||||
|
(
|
||||||
|
gitea_instance, authorization_endpoint,
|
||||||
|
token_endpoint, userinfo_endpoint,
|
||||||
|
introspection_endpoint
|
||||||
|
) VALUES (
|
||||||
|
(SELECT ID FROM librepages_gitea_instances WHERE url = $1)
|
||||||
|
, $2, $3, $4, $5
|
||||||
|
)",
|
||||||
|
&url.as_str(),
|
||||||
|
&payload.authorization_endpoint.as_str(),
|
||||||
|
&payload.token_endpoint.as_str(),
|
||||||
|
&payload.userinfo_endpoint.as_str(),
|
||||||
|
&payload.introspection_endpoint.as_str(),
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(map_register_err)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_gitea_oidc_configuration(
|
||||||
|
&self,
|
||||||
|
url: &Url,
|
||||||
|
) -> ServiceResult<OIDCConfiguration> {
|
||||||
|
struct OIDCConfigurationInner {
|
||||||
|
authorization_endpoint: String,
|
||||||
|
token_endpoint: String,
|
||||||
|
userinfo_endpoint: String,
|
||||||
|
introspection_endpoint: String,
|
||||||
|
}
|
||||||
|
let res = sqlx::query_as!(
|
||||||
|
OIDCConfigurationInner,
|
||||||
|
"SELECT
|
||||||
|
authorization_endpoint, token_endpoint,
|
||||||
|
userinfo_endpoint, introspection_endpoint
|
||||||
|
FROM
|
||||||
|
librepages_gitea_oidc_configuration
|
||||||
|
WHERE
|
||||||
|
gitea_instance = (SELECT ID FROM librepages_gitea_instances WHERE url = $1)",
|
||||||
|
url.as_str()
|
||||||
|
)
|
||||||
|
.fetch_one(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, ServiceError::GiteaInstanceNotFound))?;
|
||||||
|
let res = OIDCConfiguration {
|
||||||
|
authorization_endpoint: Url::parse(&res.authorization_endpoint)?,
|
||||||
|
token_endpoint: Url::parse(&res.token_endpoint)?,
|
||||||
|
userinfo_endpoint: Url::parse(&res.userinfo_endpoint)?,
|
||||||
|
introspection_endpoint: Url::parse(&res.introspection_endpoint)?,
|
||||||
|
};
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
struct InnerSite {
|
struct InnerSite {
|
||||||
site_secret: String,
|
site_secret: String,
|
||||||
|
@ -731,6 +830,19 @@ pub struct LibrePagesEvent {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct GiteaInstance {
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct AddGiteaInstance {
|
||||||
|
pub url: Url,
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn now_unix_time_stamp() -> OffsetDateTime {
|
fn now_unix_time_stamp() -> OffsetDateTime {
|
||||||
OffsetDateTime::now_utc()
|
OffsetDateTime::now_utc()
|
||||||
}
|
}
|
||||||
|
@ -769,6 +881,13 @@ fn map_register_err(e: sqlx::Error) -> ServiceError {
|
||||||
ServiceError::UsernameTaken
|
ServiceError::UsernameTaken
|
||||||
} else if msg.contains("librepages_users_email_key") {
|
} else if msg.contains("librepages_users_email_key") {
|
||||||
ServiceError::EmailTaken
|
ServiceError::EmailTaken
|
||||||
|
} else if msg.contains("librepages_gitea_instances_url_key")
|
||||||
|
|| msg.contains("librepages_gitea_oidc_configuration_authorization_endpoint_key")
|
||||||
|
|| msg.contains("librepages_gitea_oidc_configuration_token_endpoint_key")
|
||||||
|
|| msg.contains("librepages_gitea_oidc_configuration_userinfo_endpoint_key")
|
||||||
|
|| msg.contains("librepages_gitea_oidc_configuration_introspection_endpoint_key")
|
||||||
|
{
|
||||||
|
ServiceError::GiteaInstanceRegistered
|
||||||
} else {
|
} else {
|
||||||
error!("{}", msg);
|
error!("{}", msg);
|
||||||
ServiceError::InternalServerError
|
ServiceError::InternalServerError
|
||||||
|
@ -1028,4 +1147,70 @@ mod tests {
|
||||||
// test if hostname exists. Should be false
|
// test if hostname exists. Should be false
|
||||||
assert!(!db.hostname_exists(&site.hostname).await.unwrap());
|
assert!(!db.hostname_exists(&site.hostname).await.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
pub async fn test_gitea_instance_methods() {
|
||||||
|
let settings = Settings::new().unwrap();
|
||||||
|
let pool_options = PgPoolOptions::new().max_connections(1);
|
||||||
|
let db = ConnectionOptions::Fresh(Fresh {
|
||||||
|
pool_options,
|
||||||
|
url: settings.database.url.clone(),
|
||||||
|
disable_logging: !settings.debug,
|
||||||
|
})
|
||||||
|
.connect()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(db.ping().await);
|
||||||
|
|
||||||
|
let url = Url::parse("https://test_gitea_instance_methods.example.org").unwrap();
|
||||||
|
let client_id = "longid";
|
||||||
|
let client_secret = "longsecret";
|
||||||
|
|
||||||
|
let _ = db.delete_gitea_instance(&url).await;
|
||||||
|
|
||||||
|
let payload = AddGiteaInstance {
|
||||||
|
client_secret: client_secret.into(),
|
||||||
|
client_id: client_id.into(),
|
||||||
|
url: url.clone(),
|
||||||
|
};
|
||||||
|
db.new_gitea_instance(&payload).await.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
db.new_gitea_instance(&payload).await.err(),
|
||||||
|
Some(ServiceError::GiteaInstanceRegistered)
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = db.get_gitea_password(&url).await.unwrap();
|
||||||
|
assert_eq!(res.client_id, client_id);
|
||||||
|
assert_eq!(res.client_secret, client_secret);
|
||||||
|
|
||||||
|
let oidc_config = OIDCConfiguration {
|
||||||
|
authorization_endpoint: Url::parse("https://example.org/authorization_endpoint")
|
||||||
|
.unwrap(),
|
||||||
|
token_endpoint: Url::parse("https://example.org/token_endpoint").unwrap(),
|
||||||
|
userinfo_endpoint: Url::parse("https://exapmle.org/userinfo_endpoint").unwrap(),
|
||||||
|
introspection_endpoint: Url::parse("https://exapmle.org/introspection_endpoint")
|
||||||
|
.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
db.new_gitea_oidc_configuration(&url, &oidc_config)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
db.new_gitea_oidc_configuration(&url, &oidc_config)
|
||||||
|
.await
|
||||||
|
.err(),
|
||||||
|
Some(ServiceError::GiteaInstanceRegistered)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
db.get_gitea_oidc_configuration(&url).await.unwrap(),
|
||||||
|
oidc_config
|
||||||
|
);
|
||||||
|
|
||||||
|
db.delete_gitea_instance(&url).await.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
db.get_gitea_password(&url).await.err(),
|
||||||
|
Some(ServiceError::GiteaInstanceNotFound)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,14 @@ pub enum ServiceError {
|
||||||
#[display(fmt = "Passwords don't match")]
|
#[display(fmt = "Passwords don't match")]
|
||||||
/// passwords don't match
|
/// passwords don't match
|
||||||
PasswordsDontMatch,
|
PasswordsDontMatch,
|
||||||
|
|
||||||
|
/// Gitea instance is registered
|
||||||
|
#[display(fmt = "Gitea instance is registered")]
|
||||||
|
GiteaInstanceRegistered,
|
||||||
|
|
||||||
|
/// Gitea instance not found
|
||||||
|
#[display(fmt = "Gitea instance not found")]
|
||||||
|
GiteaInstanceNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParseError> for ServiceError {
|
impl From<ParseError> for ServiceError {
|
||||||
|
@ -252,6 +260,9 @@ impl ResponseError for ServiceError {
|
||||||
ServiceError::ClosedForRegistration => StatusCode::FORBIDDEN, //FORBIDDEN,
|
ServiceError::ClosedForRegistration => StatusCode::FORBIDDEN, //FORBIDDEN,
|
||||||
ServiceError::NotAnEmail => StatusCode::BAD_REQUEST, //BADREQUEST,
|
ServiceError::NotAnEmail => StatusCode::BAD_REQUEST, //BADREQUEST,
|
||||||
ServiceError::WrongPassword => StatusCode::UNAUTHORIZED, //UNAUTHORIZED,
|
ServiceError::WrongPassword => StatusCode::UNAUTHORIZED, //UNAUTHORIZED,
|
||||||
|
//
|
||||||
|
ServiceError::GiteaInstanceRegistered => StatusCode::BAD_REQUEST,
|
||||||
|
ServiceError::GiteaInstanceNotFound => StatusCode::NOT_FOUND,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
118
src/pages/auth/gitea/add.rs
Normal file
118
src/pages/auth/gitea/add.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use actix_web::http::header::ContentType;
|
||||||
|
use tera::Context;
|
||||||
|
|
||||||
|
use crate::db::AddGiteaInstance;
|
||||||
|
use crate::pages::errors::*;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
use crate::AppCtx;
|
||||||
|
|
||||||
|
pub use super::*;
|
||||||
|
|
||||||
|
pub struct GiteaAddInstanceTemplate {
|
||||||
|
ctx: RefCell<Context>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const GITEA_ADD_INSTANCE: TemplateFile =
|
||||||
|
TemplateFile::new("gitea_add_instance", "pages/auth/gitea/add.html");
|
||||||
|
|
||||||
|
impl CtxError for GiteaAddInstanceTemplate {
|
||||||
|
fn with_error(&self, e: &ReadableError) -> String {
|
||||||
|
self.ctx.borrow_mut().insert(ERROR_KEY, e);
|
||||||
|
self.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GiteaAddInstanceTemplate {
|
||||||
|
pub fn new(settings: &Settings, payload: Option<&AddGiteaInstance>) -> Self {
|
||||||
|
let ctx = RefCell::new(context(settings));
|
||||||
|
if let Some(payload) = payload {
|
||||||
|
ctx.borrow_mut().insert(PAYLOAD_KEY, payload);
|
||||||
|
}
|
||||||
|
Self { ctx }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self) -> String {
|
||||||
|
TEMPLATES
|
||||||
|
.render(GITEA_ADD_INSTANCE.name, &self.ctx.borrow())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page(s: &Settings) -> String {
|
||||||
|
let p = Self::new(s, None);
|
||||||
|
p.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web_codegen_const_routes::get(path = "PAGES.auth.gitea.add")]
|
||||||
|
#[tracing::instrument(name = "Serve add Gitea instance page", skip(ctx))]
|
||||||
|
pub async fn get_gitea_add_instance(ctx: AppCtx) -> impl Responder {
|
||||||
|
let login = GiteaAddInstanceTemplate::page(&ctx.settings);
|
||||||
|
let html = ContentType::html();
|
||||||
|
HttpResponse::Ok().content_type(html).body(login)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
|
cfg.service(get_gitea_add_instance);
|
||||||
|
cfg.service(post_gitea_add_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web_codegen_const_routes::post(path = "PAGES.auth.gitea.add")]
|
||||||
|
#[tracing::instrument(name = "Submit new Gitea instance", skip(payload, ctx))]
|
||||||
|
pub async fn post_gitea_add_instance(
|
||||||
|
payload: web::Form<AddGiteaInstance>,
|
||||||
|
ctx: AppCtx,
|
||||||
|
) -> PageResult<impl Responder, GiteaAddInstanceTemplate> {
|
||||||
|
let payload = payload.into_inner();
|
||||||
|
ctx.init_gitea_instance(&payload).await.map_err(|e| {
|
||||||
|
PageError::new(
|
||||||
|
GiteaAddInstanceTemplate::new(&ctx.settings, Some(&payload)),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(HttpResponse::Found()
|
||||||
|
.insert_header((http::header::LOCATION, PAGES.dash.home))
|
||||||
|
.finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use super::GiteaAddInstanceTemplate;
|
||||||
|
use crate::db::AddGiteaInstance;
|
||||||
|
use crate::errors::*;
|
||||||
|
use crate::pages::errors::*;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gitea_add_instnace_page_renders() {
|
||||||
|
let settings = Settings::new().unwrap();
|
||||||
|
GiteaAddInstanceTemplate::page(&settings);
|
||||||
|
let payload = AddGiteaInstance {
|
||||||
|
client_id: "foo".into(),
|
||||||
|
client_secret: "foo".into(),
|
||||||
|
url: Url::parse("https://example.org").unwrap(),
|
||||||
|
};
|
||||||
|
let page = GiteaAddInstanceTemplate::new(&settings, Some(&payload));
|
||||||
|
page.with_error(&ReadableError::new(&ServiceError::WrongPassword));
|
||||||
|
page.render();
|
||||||
|
}
|
||||||
|
}
|
32
src/pages/auth/gitea/mod.rs
Normal file
32
src/pages/auth/gitea/mod.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use actix_web::*;
|
||||||
|
|
||||||
|
pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES};
|
||||||
|
|
||||||
|
pub mod add;
|
||||||
|
|
||||||
|
pub fn register_templates(t: &mut tera::Tera) {
|
||||||
|
for template in [add::GITEA_ADD_INSTANCE].iter() {
|
||||||
|
template.register(t).expect(template.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
|
add::services(cfg)
|
||||||
|
}
|
118
src/pages/auth/gitea/search.rs
Normal file
118
src/pages/auth/gitea/search.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use actix_web::http::header::ContentType;
|
||||||
|
use tera::Context;
|
||||||
|
|
||||||
|
use crate::db::AddGiteaInstance;
|
||||||
|
use crate::pages::errors::*;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
use crate::AppCtx;
|
||||||
|
|
||||||
|
pub use super::*;
|
||||||
|
|
||||||
|
pub struct GiteaAddInstanceTemplate {
|
||||||
|
ctx: RefCell<Context>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const GITEA_SEARCH_INSTANCE: TemplateFile =
|
||||||
|
TemplateFile::new("gitea_add_instance", "pages/auth/gitea/add.html");
|
||||||
|
|
||||||
|
impl CtxError for GiteaAddInstanceTemplate {
|
||||||
|
fn with_error(&self, e: &ReadableError) -> String {
|
||||||
|
self.ctx.borrow_mut().insert(ERROR_KEY, e);
|
||||||
|
self.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GiteaAddInstanceTemplate {
|
||||||
|
pub fn new(settings: &Settings, payload: Option<&AddGiteaInstance>) -> Self {
|
||||||
|
let ctx = RefCell::new(context(settings));
|
||||||
|
if let Some(payload) = payload {
|
||||||
|
ctx.borrow_mut().insert(PAYLOAD_KEY, payload);
|
||||||
|
}
|
||||||
|
Self { ctx }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self) -> String {
|
||||||
|
TEMPLATES
|
||||||
|
.render(GITEA_SEARCH_INSTANCE.name, &self.ctx.borrow())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page(s: &Settings) -> String {
|
||||||
|
let p = Self::new(s, None);
|
||||||
|
p.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web_codegen_const_routes::get(path = "PAGES.auth.gitea.add")]
|
||||||
|
#[tracing::instrument(name = "Serve add Gitea instance page", skip(ctx))]
|
||||||
|
pub async fn get_gitea_add_instance(ctx: AppCtx) -> impl Responder {
|
||||||
|
let login = GiteaAddInstanceTemplate::page(&ctx.settings);
|
||||||
|
let html = ContentType::html();
|
||||||
|
HttpResponse::Ok().content_type(html).body(login)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
|
cfg.service(get_gitea_add_instance);
|
||||||
|
cfg.service(post_gitea_add_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web_codegen_const_routes::post(path = "PAGES.auth.gitea.add")]
|
||||||
|
#[tracing::instrument(name = "Submit new Gitea instance", skip(payload, ctx))]
|
||||||
|
pub async fn post_gitea_add_instance(
|
||||||
|
payload: web::Form<AddGiteaInstance>,
|
||||||
|
ctx: AppCtx,
|
||||||
|
) -> PageResult<impl Responder, GiteaAddInstanceTemplate> {
|
||||||
|
let payload = payload.into_inner();
|
||||||
|
ctx.init_gitea_instance(&payload).await.map_err(|e| {
|
||||||
|
PageError::new(
|
||||||
|
GiteaAddInstanceTemplate::new(&ctx.settings, Some(&payload)),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(HttpResponse::Found()
|
||||||
|
.insert_header((http::header::LOCATION, PAGES.dash.home))
|
||||||
|
.finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use super::GiteaAddInstanceTemplate;
|
||||||
|
use crate::db::AddGiteaInstance;
|
||||||
|
use crate::errors::*;
|
||||||
|
use crate::pages::errors::*;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gitea_add_instnace_page_renders() {
|
||||||
|
let settings = Settings::new().unwrap();
|
||||||
|
GiteaAddInstanceTemplate::page(&settings);
|
||||||
|
let payload = AddGiteaInstance {
|
||||||
|
client_id: "foo".into(),
|
||||||
|
client_secret: "foo".into(),
|
||||||
|
url: Url::parse("https://example.org").unwrap(),
|
||||||
|
};
|
||||||
|
let page = GiteaAddInstanceTemplate::new(&settings, Some(&payload));
|
||||||
|
page.with_error(&ReadableError::new(&ServiceError::WrongPassword));
|
||||||
|
page.render();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ use actix_web::*;
|
||||||
|
|
||||||
pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES};
|
pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES};
|
||||||
|
|
||||||
|
pub mod gitea;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -30,12 +31,14 @@ pub fn register_templates(t: &mut tera::Tera) {
|
||||||
for template in [AUTH_BASE, login::LOGIN, register::REGISTER].iter() {
|
for template in [AUTH_BASE, login::LOGIN, register::REGISTER].iter() {
|
||||||
template.register(t).expect(template.name);
|
template.register(t).expect(template.name);
|
||||||
}
|
}
|
||||||
|
gitea::register_templates(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(signout);
|
cfg.service(signout);
|
||||||
register::services(cfg);
|
register::services(cfg);
|
||||||
login::services(cfg);
|
login::services(cfg);
|
||||||
|
gitea::services(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web_codegen_const_routes::get(
|
#[actix_web_codegen_const_routes::get(
|
||||||
|
|
|
@ -41,6 +41,25 @@ impl Pages {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
/// Gitea authentication routes
|
||||||
|
pub struct Gitea {
|
||||||
|
/// add Gitea instance route
|
||||||
|
pub add: &'static str,
|
||||||
|
/// search Gitea instance route
|
||||||
|
pub search: &'static str,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gitea {
|
||||||
|
/// create new instance of Authentication route
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
let add = "/gitea/add";
|
||||||
|
let search = "/gitea/search";
|
||||||
|
Self { add, search }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
/// Authentication routes
|
/// Authentication routes
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
|
@ -50,6 +69,8 @@ pub struct Auth {
|
||||||
pub login: &'static str,
|
pub login: &'static str,
|
||||||
/// registration route
|
/// registration route
|
||||||
pub register: &'static str,
|
pub register: &'static str,
|
||||||
|
/// gitea authentication routes
|
||||||
|
pub gitea: Gitea,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Auth {
|
impl Auth {
|
||||||
|
@ -58,10 +79,12 @@ impl Auth {
|
||||||
let login = "/login";
|
let login = "/login";
|
||||||
let logout = "/logout";
|
let logout = "/logout";
|
||||||
let register = "/join";
|
let register = "/join";
|
||||||
|
let gitea = Gitea::new();
|
||||||
Auth {
|
Auth {
|
||||||
logout,
|
logout,
|
||||||
login,
|
login,
|
||||||
register,
|
register,
|
||||||
|
gitea,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
62
templates/pages/auth/gitea/add.html
Normal file
62
templates/pages/auth/gitea/add.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{% extends 'authbase' %}
|
||||||
|
{% block login %}
|
||||||
|
<h2>Add Gitea Instance</h2>
|
||||||
|
<form action="{{ page.auth.gitea.add }}" method="POST" class="auth-form" accept-charset="utf-8">
|
||||||
|
{% include "error_comp" %}
|
||||||
|
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="url">
|
||||||
|
Gitea URL
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="url"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
id="url"
|
||||||
|
type="url"
|
||||||
|
{% if payload.url %}
|
||||||
|
value={{ payload.url }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="client_id">
|
||||||
|
Client ID
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="client_id"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
id="client_id"
|
||||||
|
type="text"
|
||||||
|
{% if payload.client_id %}
|
||||||
|
value={{ payload.client_id }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="client_secret">
|
||||||
|
Client Secret
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="client_secret"
|
||||||
|
required
|
||||||
|
id="client_secret"
|
||||||
|
type="password"
|
||||||
|
{% if payload.client_secret %}
|
||||||
|
value={{ payload.client_secret }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="auth-form__action-container">
|
||||||
|
<button class="auth-form__submit" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<p class="auth-form__alt-action">
|
||||||
|
New to LibrePages?
|
||||||
|
<a href="{{ page.auth.register }}">Create an account </a>
|
||||||
|
</p>
|
||||||
|
-->
|
||||||
|
{% endblock %}
|
62
templates/pages/auth/gitea/login.html
Normal file
62
templates/pages/auth/gitea/login.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{% extends 'authbase' %}
|
||||||
|
{% block login %}
|
||||||
|
<h2>Add Gitea Instance</h2>
|
||||||
|
<form action="{{ page.auth.gitea.add }}" method="POST" class="auth-form" accept-charset="utf-8">
|
||||||
|
{% include "error_comp" %}
|
||||||
|
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="url">
|
||||||
|
Gitea URL
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="url"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
id="url"
|
||||||
|
type="url"
|
||||||
|
{% if payload.url %}
|
||||||
|
value={{ payload.url }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="client_id">
|
||||||
|
Client ID
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="client_id"
|
||||||
|
autofocus
|
||||||
|
required
|
||||||
|
id="client_id"
|
||||||
|
type="text"
|
||||||
|
{% if payload.client_id %}
|
||||||
|
value={{ payload.client_id }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="auth-form__label" for="client_secret">
|
||||||
|
Client Secret
|
||||||
|
<input
|
||||||
|
class="auth-form__input"
|
||||||
|
name="client_secret"
|
||||||
|
required
|
||||||
|
id="client_secret"
|
||||||
|
type="password"
|
||||||
|
{% if payload.client_secret %}
|
||||||
|
value={{ payload.client_secret }}
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div class="auth-form__action-container">
|
||||||
|
<button class="auth-form__submit" type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<p class="auth-form__alt-action">
|
||||||
|
New to LibrePages?
|
||||||
|
<a href="{{ page.auth.register }}">Create an account </a>
|
||||||
|
</p>
|
||||||
|
-->
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue