mirror of
https://github.com/renorris/openfsd
synced 2026-03-22 14:35:36 +08:00
initial v1.0-beta commit
This commit is contained in:
3
web/javascript/.gitignore
vendored
Normal file
3
web/javascript/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
1
web/javascript/README.txt
Normal file
1
web/javascript/README.txt
Normal file
@@ -0,0 +1 @@
|
||||
Typescript source for frontend UI application
|
||||
3935
web/javascript/package-lock.json
generated
Normal file
3935
web/javascript/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
web/javascript/package.json
Normal file
23
web/javascript/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "openfsd-frontend",
|
||||
"version": "1.0.0",
|
||||
"description": "Frontend javascript for openfsd web interface",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.32",
|
||||
"ts-loader": "^9.5.2",
|
||||
"typescript": "^5.8.3",
|
||||
"webpack": "^5.99.7",
|
||||
"webpack-cli": "^6.0.1",
|
||||
"webpack-dev-server": "^5.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"jose": "^6.0.10",
|
||||
"jquery": "^3.7.1"
|
||||
}
|
||||
}
|
||||
84
web/javascript/src/api/api.ts
Normal file
84
web/javascript/src/api/api.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import $ from "jquery";
|
||||
import jqXHR = JQuery.jqXHR;
|
||||
import { decodeJwt } from "jose";
|
||||
|
||||
interface APIV1Response {
|
||||
version: string,
|
||||
err: string | null,
|
||||
data: any | null,
|
||||
}
|
||||
|
||||
export async function doAPIRequest(method: string, url: string, withAuth: boolean, data: any): Promise<APIV1Response> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let accessToken = "";
|
||||
if (withAuth) {
|
||||
accessToken = await getAccessToken();
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
method: method,
|
||||
headers: withAuth ? {"Authorization": `Bearer ${accessToken}`} : {},
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
dataType: "json",
|
||||
}).done((data) => {
|
||||
resolve(data)
|
||||
}).fail((data) => {
|
||||
resolve(data)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function doAPIRequestWithoutBearerToken(method: string, url: string, data: any): Promise<jqXHR> {
|
||||
return $.ajax(url, {
|
||||
method: method,
|
||||
data: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
async function doAPIRequestWithBearerToken(method: string, url: string, data: any): Promise<jqXHR> {
|
||||
const accessToken = await getAccessToken();
|
||||
|
||||
return $.ajax(url, {
|
||||
method: method,
|
||||
headers: {"Authorization": `Bearer ${accessToken}`},
|
||||
data: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
||||
// getAccessToken returns the current valid access token.
|
||||
// An exception is thrown if no token is found, an error occurs refreshing the access token,
|
||||
// or if the refresh token is expired.
|
||||
async function getAccessToken(): Promise<string> {
|
||||
const storedAccessToken = localStorage.getItem("access_token")!;
|
||||
const jwtPayload = decodeJwt(storedAccessToken);
|
||||
const exp = jwtPayload.exp!;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (exp < (now + 15)) { // Assuming corrected logic
|
||||
const newAccessToken = await refreshAccessToken();
|
||||
localStorage.setItem("access_token", newAccessToken);
|
||||
return newAccessToken;
|
||||
}
|
||||
return storedAccessToken;
|
||||
}
|
||||
|
||||
async function refreshAccessToken(): Promise<string> {
|
||||
const storedRefreshToken = localStorage.getItem("refresh_token")!;
|
||||
const jwtPayload = decodeJwt(storedRefreshToken);
|
||||
const exp = jwtPayload.exp!;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (exp < (now + 15)) {
|
||||
throw new Error("refresh token expired");
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
$.ajax({
|
||||
url: "/api/v1/auth/refresh",
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({ 'refresh_token': storedRefreshToken }),
|
||||
}).done((data) => resolve(data['access_token']))
|
||||
.fail(() => reject(new Error("failed to refresh access token")));
|
||||
});
|
||||
}
|
||||
1
web/javascript/src/index.ts
Normal file
1
web/javascript/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './pages/login/login'
|
||||
22
web/javascript/src/pages/login/login.ts
Normal file
22
web/javascript/src/pages/login/login.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
import { doAPIRequest } from "../../api/api";
|
||||
|
||||
$("#login-form").on('submit', async (ev) => {
|
||||
ev.preventDefault()
|
||||
|
||||
const requestBody = {
|
||||
'cid': $("#login-input-cid").val() as string,
|
||||
'password': $("#login-input-password").val(),
|
||||
'remember_me': $("#login-input-remember-me").prop('checked')
|
||||
}
|
||||
|
||||
const res = await doAPIRequest('POST', '/api/v1/auth/login', false, requestBody);
|
||||
if (res.err !== null) {
|
||||
alert(`Error signing in: ${res.err}`);
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.setItem("access_token", res.data['access_token'])
|
||||
localStorage.setItem("refresh_token", res.data['refresh_token'])
|
||||
})
|
||||
11
web/javascript/tsconfig.json
Normal file
11
web/javascript/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"outDir": "./dist/",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
22
web/javascript/webpack.config.js
Normal file
22
web/javascript/webpack.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.ts',
|
||||
output: {
|
||||
filename: 'openfsd-bundle.js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
mode: "production",
|
||||
};
|
||||
Reference in New Issue
Block a user