diff --git a/go.mod b/go.mod index c4fb6c4..9672f07 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,37 @@ module github.com/veypi/OneAuth -go 1.16 +go 1.21 require ( - github.com/json-iterator/go v1.1.10 + github.com/json-iterator/go v1.1.12 github.com/olivere/elastic/v7 v7.0.29 github.com/urfave/cli/v2 v2.2.0 github.com/veypi/OneBD v0.4.3 github.com/veypi/utils v0.3.1 + golang.org/x/net v0.0.0-20210614182718-04defd469f4e gorm.io/driver/mysql v1.0.5 gorm.io/driver/sqlite v1.1.4 gorm.io/gorm v1.21.3 ) +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kardianos/service v1.1.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-sqlite3 v1.14.5 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rs/zerolog v1.17.2 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + golang.org/x/sys v0.0.0-20210423082822-04245dca01da // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect +) + replace github.com/veypi/OneBD v0.4.3 => ../OceanCurrent/OneBD diff --git a/go.sum b/go.sum index b78a7db..e58676b 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kardianos/service v1.1.0 h1:QV2SiEeWK42P0aEmGcsAgjApw/lRxkwopvT+Gu6t1/0= github.com/kardianos/service v1.1.0/go.mod h1:RrJI2xn5vve/r32U5suTbeaSGoMU6GbNPoj36CVYcHc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -65,8 +65,8 @@ github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KK github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/olivere/elastic/v7 v7.0.29 h1:zvorjSPHFli/0owqfoLq0ZOtVhZSyHsMbRi29Vj7T14= github.com/olivere/elastic/v7 v7.0.29/go.mod h1:8PlkMD2Xb690IPhIPii2SypuuXtXX3dDcSKGqnEGXzE= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= diff --git a/libs/base/api_handler.go b/libs/base/api_handler.go index e49a71c..9db8b5c 100644 --- a/libs/base/api_handler.go +++ b/libs/base/api_handler.go @@ -41,6 +41,8 @@ func JSONResponse(m OneBD.Meta, data interface{}, err error) { res["err"] = err.Error() } else { res["status"] = 1 + } + if data != nil { res["content"] = data } p, err := json.Marshal(res) diff --git a/oab/Cargo.toml b/oab/Cargo.toml index 5a68ada..57e8a6c 100644 --- a/oab/Cargo.toml +++ b/oab/Cargo.toml @@ -21,6 +21,11 @@ thiserror = "1.0" sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "mysql", "macros", "migrate", "chrono"] } +sea-orm = { version = "^0.12.0", features = [ "sqlx-mysql", + "runtime-tokio-rustls", "macros", "debug-print", "with-chrono", + "with-json", "with-uuid" ] } + + actix-web = "4" actix-files = "0.6.2" jsonwebtoken = "8" diff --git a/oab/migrations/20220720220617_base.sql b/oab/migrations/20220720220617_base.sql index 51c9254..6a1612c 100644 --- a/oab/migrations/20220720220617_base.sql +++ b/oab/migrations/20220720220617_base.sql @@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS `user` `id` varchar(32) NOT NULL DEFAULT '' COMMENT 'User UUID', `created` datetime DEFAULT CURRENT_TIMESTAMP, `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_flag` tinyint(1) NOT NULL, + `delete_flag` tinyint(1) NOT NULL DEFAULT 0, `username` varchar(255) NOT NULL UNIQUE, `nickname` varchar(255), @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `user` `real_code` varchar(32), `check_code` binary(48), - `status` int NOT NULL COMMENT '状态(0:ok,1:disabled)', + `status` int NOT NULL COMMENT '状态(0:ok,1:disabled)' DEFAULT 0, `used` int NOT NULL DEFAULT 0, `space` int DEFAULT 300, @@ -32,7 +32,7 @@ CREATE TABLE IF NOT EXISTS `app` `id` varchar(32) NOT NULL, `created` datetime DEFAULT CURRENT_TIMESTAMP, `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_flag` tinyint(1) NOT NULL, + `delete_flag` tinyint(1) NOT NULL DEFAULT 0, `key` varchar(32) NOT NULL, `name` varchar(255) NOT NULL, @@ -44,7 +44,7 @@ CREATE TABLE IF NOT EXISTS `app` `role_id` varchar(32), `redirect` varchar(255), - `status` int NOT NULL COMMENT '状态(0:ok,1:disabled)', + `status` int NOT NULL COMMENT '状态(0:ok,1:disabled)' DEFAULT 0, PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -56,7 +56,7 @@ CREATE TABLE IF NOT EXISTS `app_user` `app_id` varchar(32) NOT NULL, `user_id` varchar(32) NOT NULL, - `status` int NOT NULL DEFAULT 0, + `status` int NOT NULL DEFAULT 0 COMMENT '0: ok,1:disabled,2:applying,3:deny', PRIMARY KEY (`user_id`,`app_id`) USING BTREE, FOREIGN KEY (`app_id`) REFERENCES `app`(`id`), @@ -70,12 +70,12 @@ CREATE TABLE IF NOT EXISTS `role` `id` varchar(32) NOT NULL, `created` datetime DEFAULT CURRENT_TIMESTAMP, `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_flag` tinyint(1) NOT NULL, + `delete_flag` tinyint(1) NOT NULL DEFAULT 0, `app_id` varchar(32) NOT NULL, `name` varchar(255) NOT NULL, `des` varchar(255), - `user_count` int NOT NULL, + `user_count` int NOT NULL DEFAULT 0, PRIMARY KEY (`id`) USING BTREE, FOREIGN KEY (`app_id`) REFERENCES `app`(`id`) @@ -88,7 +88,7 @@ CREATE TABLE IF NOT EXISTS `user_role` `user_id` varchar(32) NOT NULL, `role_id` varchar(32) NOT NULL, - `status` varchar(32) NOT NULL, + `status` varchar(32) NOT NULL DEFAULT 0, PRIMARY KEY (`user_id`,`role_id`) USING BTREE, FOREIGN KEY (`role_id`) REFERENCES `role`(`id`), @@ -99,7 +99,7 @@ CREATE TABLE IF NOT EXISTS `resource` ( `created` datetime DEFAULT CURRENT_TIMESTAMP, `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_flag` tinyint(1) NOT NULL, + `delete_flag` tinyint(1) NOT NULL DEFAULT 0, `app_id` varchar(32) NOT NULL, `name` varchar(32) NOT NULL, @@ -113,9 +113,10 @@ CREATE TABLE IF NOT EXISTS `resource` CREATE TABLE IF NOT EXISTS `access` ( + `id` int NOT NULL AUTO_INCREMENT, `created` datetime DEFAULT CURRENT_TIMESTAMP, `updated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `delete_flag` tinyint(1) NOT NULL, + `delete_flag` tinyint(1) NOT NULL DEFAULT 0, `app_id` varchar(32) NOT NULL, `name` varchar(32) NOT NULL, @@ -126,6 +127,7 @@ CREATE TABLE IF NOT EXISTS `access` `level` int DEFAULT 0, -- PRIMARY KEY (`app_id`,`name`, `role_id`, `user_id`) USING BTREE, + PRIMARY KEY (`id`), FOREIGN KEY (`role_id`) REFERENCES `role`(`id`), FOREIGN KEY (`user_id`) REFERENCES `user`(`id`), FOREIGN KEY (`app_id`,`name`) REFERENCES `resource`(`app_id`,`name`) @@ -144,8 +146,8 @@ INSERT INTO `role` (`id`, `app_id`, `name`) VALUES ('1lytMwQL4uiNd0vsc', 'FR9P5t8debxc11aFF', 'admin'); INSERT INTO `access` (`app_id`, `name`, `role_id`, `user_id`,`level`) -VALUES ('FR9P5t8debxc11aFF', 'app', '1lytMwQL4uiNd0vsc', NULL,6), -('FR9P5t8debxc11aFF', 'user', '1lytMwQL4uiNd0vsc', NULL,6); +VALUES ('FR9P5t8debxc11aFF', 'app', '1lytMwQL4uiNd0vsc', NULL,5), +('FR9P5t8debxc11aFF', 'user', '1lytMwQL4uiNd0vsc', NULL,5); diff --git a/oab/src/api/appuser.rs b/oab/src/api/appuser.rs new file mode 100644 index 0000000..8c149fd --- /dev/null +++ b/oab/src/api/appuser.rs @@ -0,0 +1,39 @@ +// +// appuser.rs +// Copyright (C) 2023 veypi +// 2023-09-30 23:11 +// Distributed under terms of the MIT license. +// + +use actix_web::{delete, get, post, web, Responder}; +use proc::access_read; +use serde::{Deserialize, Serialize}; +use tracing::info; + +use crate::{models, Error, Result, CONFIG}; + +#[get("/app/{aid}/user/{uid}")] +#[access_read("app")] +pub async fn get(params: web::Path<(String, String)>) -> Result { + let (mut aid, mut uid) = params.into_inner(); + if uid == "-" { + uid = "".to_string(); + } + if aid == "-" { + aid = "".to_string(); + } + let sql = format!("select * from app_user where"); + info!("111|{}|{}|", aid, uid); + if uid.is_empty() && aid.is_empty() { + Err(Error::Missing("uid or aid".to_string())) + } else { + let s = sqlx::query_as::<_, models::AppUser>( + "select * from app_user where app_id = ? and user_id = ?", + ) + .bind(aid) + .bind(uid) + .fetch_all(CONFIG.db()) + .await?; + Ok(web::Json(s)) + } +} diff --git a/oab/src/api/mod.rs b/oab/src/api/mod.rs index 7c3b0d9..756ad74 100644 --- a/oab/src/api/mod.rs +++ b/oab/src/api/mod.rs @@ -8,6 +8,7 @@ mod access; mod app; +mod appuser; mod resource; mod role; mod user; @@ -34,5 +35,8 @@ pub fn routes(cfg: &mut web::ServiceConfig) { .service(app::list) .service(app::create) .service(app::del); + + cfg.service(appuser::get); + cfg.service(greet); } diff --git a/oab/src/api/user.rs b/oab/src/api/user.rs index 2534579..955e4d1 100644 --- a/oab/src/api/user.rs +++ b/oab/src/api/user.rs @@ -184,7 +184,7 @@ pub struct RegisterOpt { pub async fn register(q: web::Json) -> Result { let q = q.into_inner(); // let mut tx = dbtx().await; - println!("{:#?}", q); + info!("{:#?}", q); let u: Option = sqlx::query_as::<_, models::User>("select * from user where username = ?") .bind(q.username.clone()) diff --git a/oab/src/cfg.rs b/oab/src/cfg.rs index 773d76f..6c67e22 100644 --- a/oab/src/cfg.rs +++ b/oab/src/cfg.rs @@ -9,7 +9,6 @@ // use std::{ - borrow::Borrow, fs::File, io::{self, Read}, }; @@ -17,7 +16,6 @@ use std::{ use clap::{Args, Parser, Subcommand}; use lazy_static::lazy_static; use sqlx::{mysql::MySqlPoolOptions, Pool}; -use tracing::log::warn; lazy_static! { pub static ref CLI: AppCli = AppCli::new(); @@ -110,7 +108,7 @@ impl ApplicationConfig { debug: true, server_url: "127.0.0.1:4001".to_string(), media_path: "/Users/veypi/test/media/".to_string(), - db_url: "127.0.0.1:3306".to_string(), + db_url: "localhost:3306".to_string(), db_user: "root".to_string(), db_pass: "123456".to_string(), db_name: "test".to_string(), diff --git a/oab/src/models/user.rs b/oab/src/models/user.rs index c009863..ab88545 100644 --- a/oab/src/models/user.rs +++ b/oab/src/models/user.rs @@ -189,6 +189,7 @@ pub enum AccessLevel { Create = 2, Update = 3, Delete = 4, + ALL = 5, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -217,7 +218,6 @@ impl Token { } } pub fn is_valid(&self) -> bool { - info!("{}/{}", self.exp, Utc::now().timestamp()); if self.exp > Utc::now().timestamp() { true } else { @@ -234,7 +234,7 @@ impl Token { } fn check(&self, domain: &str, did: &str, l: AccessLevel) -> bool { - println!("{:#?}|{:#?}|{}|", self.access, domain, did); + info!("{:#?}|{:#?}|{}|", self.access, domain, did); match &self.access { Some(ac) => { for ele in ac { diff --git a/oaweb/.eslintignore b/oaweb/.eslintignore index 6c70242..a19ad08 100644 --- a/oaweb/.eslintignore +++ b/oaweb/.eslintignore @@ -6,3 +6,4 @@ .eslintrc.js /src-ssr /quasar.config.*.temporary.compiled* +/src/libs/ diff --git a/oaweb/.eslintrc.cjs b/oaweb/.eslintrc.cjs index 796b2e8..fa08b22 100644 --- a/oaweb/.eslintrc.cjs +++ b/oaweb/.eslintrc.cjs @@ -9,7 +9,7 @@ module.exports = { // `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted parserOptions: { parser: require.resolve('@typescript-eslint/parser'), - extraFileExtensions: [ '.vue' ] + extraFileExtensions: ['.vue'] }, env: { @@ -47,11 +47,11 @@ module.exports = { // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files // required to lint *.vue files 'vue' - + // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674 // Prettier has not been included as plugin to avoid performance impact // add it as an extension for your IDE - + ], globals: { @@ -69,7 +69,11 @@ module.exports = { // add your custom rules here rules: { - + '@typescript-eslint/no-empty-function': 0, + 'vue/multi-word-component-names': 0, + '@typescript-eslint/no-unused-vars': 0, + '@typescript-eslint/no-explicit-any': 0, + 'prefer-promise-reject-errors': 'off', quotes: ['warn', 'single', { avoidEscape: true }], diff --git a/oaweb/index.html b/oaweb/index.html index 3c8c78f..a44f3f8 100644 --- a/oaweb/index.html +++ b/oaweb/index.html @@ -1,21 +1,24 @@ - - <%= productName %> - - - - - + + + OA + + + + + + + + + + + + +
+ + - - - - - - - - - diff --git a/oaweb/package.json b/oaweb/package.json index e874b78..9d57ddb 100644 --- a/oaweb/package.json +++ b/oaweb/package.json @@ -14,7 +14,9 @@ }, "dependencies": { "@quasar/extras": "^1.16.4", + "@veypi/msg": "^0.1.0", "axios": "^1.2.1", + "js-base64": "^3.7.5", "pinia": "^2.0.11", "quasar": "^2.6.0", "vue": "^3.0.0", diff --git a/oaweb/public/favicon.ico b/oaweb/public/favicon.ico index ae7bbdb..e26bc40 100644 Binary files a/oaweb/public/favicon.ico and b/oaweb/public/favicon.ico differ diff --git a/oaweb/quasar.config.js b/oaweb/quasar.config.js index 2461433..b7a2d28 100644 --- a/oaweb/quasar.config.js +++ b/oaweb/quasar.config.js @@ -14,8 +14,11 @@ const path = require('path'); module.exports = configure(function(/* ctx */) { return { + resolve: { + }, + eslint: { - // fix: true, + fix: true, // include: [], // exclude: [], // rawOptions: {}, @@ -31,7 +34,8 @@ module.exports = configure(function(/* ctx */) { // https://v2.quasar.dev/quasar-cli-vite/boot-files boot: [ 'i18n', - 'axios', + 'api', + 'pack', ], // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css @@ -123,7 +127,11 @@ module.exports = configure(function(/* ctx */) { // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework framework: { - config: {}, + config: { + loadingBar: { + + } + }, // iconSet: 'material-icons', // Quasar icon set // lang: 'en-US', // Quasar language pack @@ -136,7 +144,9 @@ module.exports = configure(function(/* ctx */) { // directives: [], // Quasar plugins - plugins: [] + plugins: [ + 'LoadingBar' + ] }, // animations: 'all', // --- includes all animations diff --git a/oaweb/src/App.vue b/oaweb/src/App.vue index fe0a246..77fc88b 100644 --- a/oaweb/src/App.vue +++ b/oaweb/src/App.vue @@ -3,5 +3,31 @@ diff --git a/oaweb/src/assets/icon.js b/oaweb/src/assets/icon.js new file mode 100644 index 0000000..47670c9 --- /dev/null +++ b/oaweb/src/assets/icon.js @@ -0,0 +1 @@ +window._iconfont_svg_string_3335115='',function(c){var t=(t=document.getElementsByTagName("script"))[t.length-1],l=t.getAttribute("data-injectcss"),t=t.getAttribute("data-disable-injectsvg");if(!t){var e,o,a,h,i,n=function(t,l){l.parentNode.insertBefore(t,l)};if(l&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}e=function(){var t,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_3335115,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(t=document.body).firstChild?n(l,t.firstChild):t.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(e,0):(o=function(){document.removeEventListener("DOMContentLoaded",o,!1),e()},document.addEventListener("DOMContentLoaded",o,!1)):document.attachEvent&&(a=e,h=c.document,i=!1,s(),h.onreadystatechange=function(){"complete"==h.readyState&&(h.onreadystatechange=null,d())})}function d(){i||(i=!0,a())}function s(){try{h.documentElement.doScroll("left")}catch(t){return void setTimeout(s,50)}d()}}(window); \ No newline at end of file diff --git a/oaweb/src/boot/api/app.ts b/oaweb/src/boot/api/app.ts new file mode 100644 index 0000000..9aeba26 --- /dev/null +++ b/oaweb/src/boot/api/app.ts @@ -0,0 +1,48 @@ +/* + * app.ts + * Copyright (C) 2023 veypi + * 2023-09-30 17:31 + * Distributed under terms of the MIT license. + */ + + +import ajax from './axios' + +export default { + local: './app/', + self() { + return ajax.get(this.local, { option: 'oa' }) + }, + getKey(uuid: string) { + return ajax.get(this.local + uuid, { option: 'key' }) + }, + create(name: string, icon: string) { + return ajax.post(this.local, { name, icon }) + }, + get(uuid: string) { + return ajax.get(this.local + uuid) + }, + list() { + return ajax.get(this.local) + }, + update(uuid: string, props: any) { + return ajax.patch(this.local + uuid, props) + }, + user(uuid: string) { + if (uuid === '') { + uuid = '-' + } + return { + local: this.local + uuid + '/user/', + list(uid: number) { + return ajax.get(this.local + uid) + }, + add(uid: number) { + return ajax.post(this.local + uid) + }, + update(uid: number, status: string) { + return ajax.patch(this.local + uid, { status }) + }, + } + }, +} diff --git a/oaweb/src/boot/api/axios.ts b/oaweb/src/boot/api/axios.ts new file mode 100644 index 0000000..24d2e3e --- /dev/null +++ b/oaweb/src/boot/api/axios.ts @@ -0,0 +1,97 @@ +/* + * axios.ts + * Copyright (C) 2023 veypi + * 2023-09-22 20:22 + * Distributed under terms of the MIT license. + */ + +import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; +import msg from '@veypi/msg' + +// Be careful when using SSR for cross-request state pollution +// due to creating a Singleton instance here; +// If any client changes this (global) instance, it might be a +// good idea to move this instance creation inside of the +// "export default () => {}" function below (which runs individually +// for each client) + +const proxy = axios.create({ + baseURL: '/api/', + withCredentials: true, + headers: { + 'content-type': 'application/json;charset=UTF-8', + }, +}); + + +// 请求拦截 +const beforeRequest = (config: any) => { + // 设置 token + const token = localStorage.getItem('auth_token') + // NOTE 添加自定义头部 + token && (config.headers.auth_token = token) + // config.headers['auth_token'] = '' + return config +} +proxy.interceptors.request.use(beforeRequest) + +// 响应拦截器 +const responseSuccess = (response: AxiosResponse) => { + // eslint-disable-next-line yoda + // 这里没有必要进行判断,axios 内部已经判断 + // const isOk = 200 <= response.status && response.status < 300 + let data = response.data + if (response.config.method === 'head') { + data = JSON.parse(JSON.stringify(response.headers)) + } + return Promise.resolve(data) +} + +const responseFailed = (error: AxiosError) => { + const { response } = error + const code = error.response?.status + const e_msg = error.response?.headers.error + if (e_msg) { + msg.Warn(e_msg) + } + if (code == 404) { + console.warn('api not exist: ') + return + } + if (response) { + return Promise.reject() + } else if (!window.navigator.onLine) { + + alert('没有网络') + return Promise.reject(new Error('请检查网络连接')) + } + return Promise.reject(error.response) +} + +proxy.interceptors.response.use(responseSuccess, responseFailed) + + +const ajax = { + get(url: string, data = {}, header?: any) { + return proxy.get(url, { params: data, headers: header }) + }, + head(url: string, data = {}, header?: any) { + return proxy.head(url, { params: data, headers: header }) + }, + delete(url: string, data = {}, header?: any) { + return proxy.delete(url, { params: data, headers: header }) + }, + + post(url: string, data = {}, header?: any) { + return proxy.post(url, data, { headers: header }) + }, + put(url: string, data = {}, header?: any) { + return proxy.put(url, data, { headers: header }) + }, + patch(url: string, data = {}, header?: any) { + return proxy.patch(url, data, { headers: header }) + }, +} + +export default ajax + diff --git a/oaweb/src/boot/api/index.ts b/oaweb/src/boot/api/index.ts new file mode 100644 index 0000000..215d0a5 --- /dev/null +++ b/oaweb/src/boot/api/index.ts @@ -0,0 +1,23 @@ +/* + * index.ts + * Copyright (C) 2023 veypi + * 2023-09-22 20:17 + * Distributed under terms of the MIT license. + */ + +import app from "./app"; +import token from "./token"; +import user from "./user"; + + + + +const api = { + user: user, + app: app, + token: token +} + + +export default api; + diff --git a/oaweb/src/boot/api/token.ts b/oaweb/src/boot/api/token.ts new file mode 100644 index 0000000..f45a541 --- /dev/null +++ b/oaweb/src/boot/api/token.ts @@ -0,0 +1,18 @@ +/* + * token.ts + * Copyright (C) 2023 veypi + * 2023-09-30 17:37 + * Distributed under terms of the MIT license. + */ + + +import ajax from './axios' + +export default (uuid: string) => { + return { + local: './app/' + uuid + '/token/', + get() { + return ajax.get(this.local) + }, + } +} diff --git a/oaweb/src/boot/api/user.ts b/oaweb/src/boot/api/user.ts new file mode 100644 index 0000000..bfbb63f --- /dev/null +++ b/oaweb/src/boot/api/user.ts @@ -0,0 +1,41 @@ + +/* + * user.ts + * Copyright (C) 2023 veypi + * 2023-09-22 20:18 + * Distributed under terms of the MIT license. + */ + + +import { Base64 } from 'js-base64' +import ajax from './axios' + +export default { + local: './user/', + register(username: string, password: string, prop?: any) { + const data = Object.assign({ + username: username, + password: Base64.encode(password), + }, prop) + return ajax.post(this.local, data) + }, + login(username: string, password: string) { + return ajax.head(this.local + username, { + typ: 'username', + password: Base64.encode(password), + }) + }, + search(q: string) { + return ajax.get(this.local, { username: q }) + }, + get(id: number) { + return ajax.get(this.local + id) + }, + list() { + return ajax.get(this.local) + }, + update(id: number, props: any) { + return ajax.patch(this.local + id, props) + }, +} + diff --git a/oaweb/src/boot/axios.ts b/oaweb/src/boot/axios.ts deleted file mode 100644 index 05a9944..0000000 --- a/oaweb/src/boot/axios.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { boot } from 'quasar/wrappers'; -import axios, { AxiosInstance } from 'axios'; - -declare module '@vue/runtime-core' { - interface ComponentCustomProperties { - $axios: AxiosInstance; - $api: AxiosInstance; - } -} - -// Be careful when using SSR for cross-request state pollution -// due to creating a Singleton instance here; -// If any client changes this (global) instance, it might be a -// good idea to move this instance creation inside of the -// "export default () => {}" function below (which runs individually -// for each client) -const api = axios.create({ baseURL: 'https://api.example.com' }); - -export default boot(({ app }) => { - // for use inside Vue files (Options API) through this.$axios and this.$api - - app.config.globalProperties.$axios = axios; - // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) - // so you won't necessarily have to import axios in each vue file - - app.config.globalProperties.$api = api; - // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) - // so you can easily perform requests against your app's API -}); - -export { api }; diff --git a/oaweb/src/boot/pack.ts b/oaweb/src/boot/pack.ts new file mode 100644 index 0000000..2d62ff1 --- /dev/null +++ b/oaweb/src/boot/pack.ts @@ -0,0 +1,18 @@ +/* + * pack.ts + * Copyright (C) 2023 veypi + * 2023-09-26 20:38 + * Distributed under terms of the MIT license. + */ + + + +import { boot } from 'quasar/wrappers' +import '@veypi/msg/index.css' +import '../assets/icon.js' + +// "async" is optional; +// more info on params: https://v2.quasar.dev/quasar-cli/boot-files +export default boot(async (/* { app, router, ... } */) => { + // something to do +}) diff --git a/oaweb/src/components/app.vue b/oaweb/src/components/app.vue new file mode 100644 index 0000000..1dc7e37 --- /dev/null +++ b/oaweb/src/components/app.vue @@ -0,0 +1,80 @@ + + + diff --git a/oaweb/src/layouts/MainLayout.vue b/oaweb/src/layouts/MainLayout.vue index f62045c..d61f00d 100644 --- a/oaweb/src/layouts/MainLayout.vue +++ b/oaweb/src/layouts/MainLayout.vue @@ -1,53 +1,54 @@ diff --git a/oaweb/src/pages/login.vue b/oaweb/src/pages/login.vue new file mode 100644 index 0000000..6fb0f83 --- /dev/null +++ b/oaweb/src/pages/login.vue @@ -0,0 +1,107 @@ + + + + diff --git a/oaweb/src/pages/register.vue b/oaweb/src/pages/register.vue new file mode 100644 index 0000000..6f773f0 --- /dev/null +++ b/oaweb/src/pages/register.vue @@ -0,0 +1,55 @@ + + + + diff --git a/oaweb/src/router/index.ts b/oaweb/src/router/index.ts index 4531114..5c6915b 100644 --- a/oaweb/src/router/index.ts +++ b/oaweb/src/router/index.ts @@ -1,4 +1,6 @@ import { route } from 'quasar/wrappers'; +import util from 'src/libs/util'; +import { useUserStore } from 'src/stores/user'; import { createMemoryHistory, createRouter, @@ -17,7 +19,7 @@ import routes from './routes'; * with the Router instance. */ -export default route(function (/* { store, ssrContext } */) { +export default route(function(/* { store, ssrContext } */) { const createHistory = process.env.SERVER ? createMemoryHistory : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory); @@ -31,6 +33,28 @@ export default route(function (/* { store, ssrContext } */) { // quasar.conf.js -> build -> publicPath history: createHistory(process.env.VUE_ROUTER_BASE), }); + const u = useUserStore() + Router.beforeEach((to, from) => { + console.log(to.meta) + if (to.meta.requiresAuth && !util.checkLogin()) { + // 此路由需要授权,请检查是否已登录 + // 如果没有,则重定向到登录页面 + return { + name: 'login', + // 保存我们所在的位置,以便以后再来 + query: { redirect: to.fullPath }, + } + } + if (to.meta.checkAuth) { + if (!to.meta.checkAuth(u.auth, to)) { + + // if (window.$msg) { + // window.$msg.warning('无权访问') + // } + return from + } + } + }) return Router; }); diff --git a/oaweb/src/router/routes.ts b/oaweb/src/router/routes.ts index 2d34fc1..87c5cf0 100644 --- a/oaweb/src/router/routes.ts +++ b/oaweb/src/router/routes.ts @@ -1,11 +1,42 @@ +import { Auths } from 'src/models/auth'; import { RouteRecordRaw } from 'vue-router'; +declare module 'vue-router' { + interface RouteMeta { + // 是可选的 + isAdmin?: boolean + title?: string + // 每个路由都必须声明 + requiresAuth: boolean + checkAuth?: (a: Auths, r?: RouteLocationNormalized) => boolean + } +} const routes: RouteRecordRaw[] = [ + { path: '/', component: () => import('layouts/MainLayout.vue'), - children: [{ path: '', component: () => import('pages/IndexPage.vue') }], + meta: { + requiresAuth: true, + }, + children: [ + { + path: '', + component: () => import('pages/IndexPage.vue') + } + ], + }, + { + path: '/login/:uuid?', + name: 'login', + component: () => import('pages/login.vue'), }, + { + path: '/register/:uuid?', + name: 'register', + component: () => import('pages/register.vue'), + }, + // Always leave this as last one, // but you can also remove it diff --git a/oaweb/src/stores/app.ts b/oaweb/src/stores/app.ts new file mode 100644 index 0000000..0a6c649 --- /dev/null +++ b/oaweb/src/stores/app.ts @@ -0,0 +1,20 @@ +/* + * app.ts + * Copyright (C) 2023 veypi + * 2023-09-30 17:26 + * Distributed under terms of the MIT license. + */ + + +import { defineStore } from 'pinia'; + +export const useAppStore = defineStore('app', { + state: () => ({ + id: '', + title: '', + }), + getters: { + }, + actions: { + }, +}); diff --git a/oaweb/src/stores/user.ts b/oaweb/src/stores/user.ts new file mode 100644 index 0000000..cf24cf5 --- /dev/null +++ b/oaweb/src/stores/user.ts @@ -0,0 +1,50 @@ +/* + * user.ts + * Copyright (C) 2023 veypi + * 2023-09-22 21:05 + * Distributed under terms of the MIT license. + */ + + +import { defineStore } from 'pinia'; +import { Auths, modelsUser, NewAuths } from 'src/models'; +import { useRouter } from 'vue-router'; +import { Base64 } from 'js-base64' +import api from 'src/boot/api'; + +export const useUserStore = defineStore('user', { + state: () => ({ + id: '', + local: {} as modelsUser, + auth: {} as Auths, + ready: false + }), + getters: { + }, + actions: { + logout() { + this.ready = false + localStorage.removeItem('auth_token') + const r = useRouter() + r.push({ name: 'login' }) + }, + fetchUserData() { + let token = localStorage.getItem('auth_token')?.split('.'); + if (!token || token.length !== 3) { + return false + } + let data = JSON.parse(Base64.decode(token[1])) + if (data.id) { + this.auth = NewAuths(data.Auth) + api.user.get(data.id).then((e: modelsUser) => { + console.log(e) + this.id = e.id + this.local = e + this.ready = true + }).catch((e) => { + this.logout() + }) + } + } + }, +}); diff --git a/oaweb/yarn.lock b/oaweb/yarn.lock index 72fc668..741e09c 100644 --- a/oaweb/yarn.lock +++ b/oaweb/yarn.lock @@ -453,6 +453,11 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@veypi/msg@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@veypi/msg/-/msg-0.1.0.tgz#2ebe899527a11ed11f68c2c96f468cfcc66ad3d4" + integrity sha512-58dj5nnpHsxaiK5sbPiDK5t8OF4uvN+kAmWhU0BRAgXHpkxkZNZ8rn7hXvSVybG1BbM8EuMNkq0lIxGYNKl8aw== + "@vitejs/plugin-vue@^2.2.0": version "2.3.4" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz#966a6279060eb2d9d1a02ea1a331af071afdcf9e" @@ -2106,6 +2111,11 @@ jiti@^1.18.2: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== +js-base64@^3.7.5: + version "3.7.5" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.5.tgz#21e24cf6b886f76d6f5f165bfcd69cc55b9e3fca" + integrity sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA== + js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"