fix login fail
Seto Elkahfi committed
Aug 5, 2024 at 15:05 UTC
b5fcd291bdb674dacf5cebb0475be627958ae6d7
11 files changed
+131
-51
.vscode/launch.json
+2
@@ -15,6 +15,8 @@
15
"--no-default-features"
16
]
17
},
18
+ // task for the `beforeDevCommand` if used, must be configured in `.vscode/tasks.json`
19
+ "preLaunchTask": "ui:dev"
20
},
21
{
22
"type": "lldb",
.vscode/settings.json
+3
@@ -5,4 +5,7 @@
5
"lib/crate_error_codes/Cargo.toml",
6
"lib/gem_error_codes/ext/gem_error_codes/Cargo.toml",
7
],
8
+ "terminal.integrated.automationProfile.osx": {
9
+ "path": "/usr/local/bin/zsh-with-rc",
10
+ }
11
}
\ No newline at end of file
.vscode/tasks.json
new
+38
@@ -0,0 +1,38 @@
1
+{
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "sf-desktop:setup",
6
+ "type": "shell",
7
+ "command": "nvm",
8
+ "args": [
9
+ "use",
10
+ ],
11
+ "isBackground": true,
12
+ "options": {
13
+ "cwd": "${workspaceFolder}/frontend/splitfire-desktop/"
14
+ }
15
+ },
16
+ {
17
+ "label": "ui:dev",
18
+ "type": "npm",
19
+ "isBackground": true,
20
+ "script": "next-dev",
21
+ "options": {
22
+ "cwd": "${workspaceFolder}/frontend/splitfire-desktop/"
23
+ },
24
+ "dependsOn": [
25
+ "sf-desktop:setup"
26
+ ]
27
+ },
28
+ {
29
+ "label": "ui:build",
30
+ "type": "npm",
31
+ "script": "next-build",
32
+ "isBackground": true,
33
+ "options": {
34
+ "cwd": "${workspaceFolder}/frontend/splitfire-desktop/"
35
+ }
36
+ }
37
+ ]
38
+}
\ No newline at end of file
backend/musik88-web/app/controllers/api/v1/user_controller.rb
+1
-1
@@ -18,7 +18,7 @@ module Api
18
render_success
19
else
20
logger.debug 'Invalid credentials.'
21
- render_error 'Invalid credentials.'
21
+ render_error(GemErrorCodes.invalid_credentials, 'Invalid credentials.', :unauthorized)
22
end
23
end
24
frontend/splitfire-desktop/app/layout.tsx
+3
-2
@@ -28,7 +28,6 @@ export default function RootLayout({
28
};
29
30
const getCurrentUser = async () => {
31
- setState(State.LOADING);
31
try {
32
const result = await db.currentUser
33
.where({ type: CurrentUserType.MAIN })
@@ -72,6 +71,7 @@ export default function RootLayout({
71
return (
72
<html lang="en" className="[color-scheme:dark]">
73
<body className="bg-gray-1100 overflow-none bg-[url('/grid.svg')] pb-36">
74
+ {state === State.LOADED && user && (
75
<Suspense>
76
<UserContext.Provider value={{ user, updateUser }}>
77
<GlobalNav />
@@ -90,7 +90,8 @@ export default function RootLayout({
90
</div>
91
</div>
92
</UserContext.Provider>
93
- </Suspense>
93
+ </Suspense>
94
+ )}
95
</body>
96
</html>
97
);
frontend/splitfire-desktop/app/login/page.tsx
+44
-27
@@ -17,6 +17,7 @@ import { Button } from "@/components/button";
17
enum State {
18
LOADING,
19
LOADED,
20
+ ERROR,
21
}
22
23
export default function Page() {
@@ -26,37 +27,46 @@ export default function Page() {
27
const [state, setState] = useState(State.LOADED);
28
const [emailOrUsername, setEmailOrUsername] = useState("");
29
const [password, setPassword] = useState("");
30
+ const [errorMessage, setErrorMessage] = useState("");
31
32
const login = async (update: (user: CurrentUser) => void) => {
31
- setState(State.LOADING);
32
- const payload = {
33
- username: emailOrUsername,
34
- password: password,
35
- };
36
- log.debug("payload", payload);
37
- const response: AccountLoginResponse = await invoke(TAURI_ACCOUNT_LOGIN, payload);
38
- log.debug("response", response);
39
- if (response.status === TauriResponse.ERROR) {
40
- console.error("Login failed", response);
41
- return;
42
- }
43
- // Sanity check
44
- if (response.user === null || response.access_token === null) {
45
- log.error("Login failed", response);
46
- return;
47
- }
33
+ try {
34
+ setState(State.LOADING);
35
+ const payload = {
36
+ username: emailOrUsername,
37
+ password: password,
38
+ };
39
+ log.debug("payload", payload);
40
+ const response: AccountLoginResponse = await invoke(TAURI_ACCOUNT_LOGIN, payload);
41
+ log.debug("response", response);
42
+ if (response.status === TauriResponse.ERROR) {
43
+ console.error("Login failed", response);
44
+ setErrorMessage(response.message);
45
+ return;
46
+ }
47
+ // Sanity check
48
+ if (response.user === null || response.access_token === null) {
49
+ log.error("Login failed", response);
50
+ setErrorMessage(response.message);
51
+ return;
52
+ }
53
49
- let currentUser: CurrentUser = {
50
- accessToken: response.access_token,
51
- type: CurrentUserType.MAIN,
52
- user: response.user,
53
- mode: Mode.Vocal
54
+ let currentUser: CurrentUser = {
55
+ accessToken: response.access_token,
56
+ type: CurrentUserType.MAIN,
57
+ user: response.user,
58
+ mode: Mode.Vocal
59
+ }
60
+ db.currentUser.add(currentUser)
61
+ // Update UserContext
62
+ update(currentUser);
63
+
64
+ router.push("/");
65
+ } catch (error) {
66
+ log.error("Login failed", error);
67
+ setErrorMessage("Login failed. Please try again.");
68
+ setState(State.ERROR);
69
}
55
- db.currentUser.add(currentUser)
56
- // Update UserContext
57
- update(currentUser);
58
-
59
- router.push("/");
70
};
71
72
if (state === State.LOADING) {
@@ -74,6 +84,13 @@ export default function Page() {
84
event.preventDefault();
85
}}
86
>
87
+ {state === State.ERROR && (
88
+ <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
89
+ <strong className="font-bold">Error!</strong>
90
+ <span className="block sm:inline">{errorMessage}</span>
91
+ </div>
92
+ )
93
+ }
94
<Form.Field className="FormField my-6" name="email">
95
<div
96
style={{
frontend/splitfire-desktop/src-tauri/src/rest/account.rs
+21
-14
@@ -5,10 +5,12 @@ use crate::{
5
},
6
models::{
7
account::{
8
- AccountLoginResponse, AccountProfileResponse, AccountRegisterResponse, ErrorResponse, LoginResponse, ProfileResponse, RegisterResponse
8
+ AccountLoginResponse, AccountProfileResponse, AccountRegisterResponse, ErrorResponse,
9
+ LoginResponse, ProfileResponse, RegisterResponse,
10
},
11
player::TauriResponse,
11
- }, rest::try_parsing_error_codes,
12
+ },
13
+ rest::try_parsing_error_codes,
14
};
15
use crate_error_codes::UserError;
16
use log::{debug, error};
@@ -17,7 +19,10 @@ use serde_json::json;
19
use tauri;
20
21
#[tauri::command]
20
-pub async fn account_login(username: String, password: String) -> Result<AccountLoginResponse, ErrorResponse> {
22
+pub async fn account_login(
23
+ username: String,
24
+ password: String,
25
+) -> Result<AccountLoginResponse, ErrorResponse> {
26
debug!(
27
"Logging in with username {}, password {}",
28
username, password
@@ -27,22 +32,14 @@ pub async fn account_login(username: String, password: String) -> Result<Account
32
"username": username,
33
"password": password
34
});
30
- let response = Client::new()
35
+ let result = Client::new()
36
.post(account_url_builder(PATH_ACCOUNT_LOGIN))
37
.json(&body)
38
.send()
39
.await;
40
36
- let ok_response = match response {
37
- Ok(response) => {
38
- match response.error_for_status() {
39
- Ok(ok_response) => ok_response,
40
- Err(e) => {
41
- debug!("Response failed: {:?}", e);
42
- return try_parsing_error_codes::<AccountLoginResponse>(response).await;
43
- }
44
- }
45
- },
41
+ let response = match result {
42
+ Ok(ok_response) => ok_response,
43
Err(e) => {
44
debug!("Failed to get response: {:?}", e);
45
return Err(ErrorResponse {
@@ -51,6 +48,16 @@ pub async fn account_login(username: String, password: String) -> Result<Account
48
});
49
}
50
};
51
+
52
+ let ok_response = match response.status() {
53
+ reqwest::StatusCode::OK => response,
54
+ _ => {
55
+ debug!("Failed to login: {:?}", response);
56
+ let error_response = try_parsing_error_codes(response).await;
57
+ return error_response;
58
+ }
59
+ };
60
+
61
let token = match ok_response.headers().get("Authorization") {
62
Some(token) => {
63
// Trim Bearer prefix
frontend/splitfire-desktop/src-tauri/src/rest/mod.rs
+1
-1
@@ -10,7 +10,7 @@ async fn try_parsing_error_codes<T>(response: Response) -> Result<T, ErrorRespon
10
let e: ErrorResponse = match response.json().await {
11
Ok(json) => json,
12
Err(e) => {
13
- error!("Failed to parse response: {:?}", e);
13
+ error!("Failed to parse error response: {:?}", e);
14
return Err(ErrorResponse {
15
error_code: UserError::ParseError,
16
message: e.to_string(),
lib/crate_error_codes/src/lib.rs
+2
@@ -9,6 +9,7 @@ use ts_rs::TS;
9
pub enum UserError {
10
// User defined error codes starts from 1000
11
UserNotFound = 1000,
12
+ InvalidCredentials = 1001,
13
14
// Generic error codes starts from 1
15
InvalidRequest = 1,
@@ -23,6 +24,7 @@ impl UserError {
24
UserError::InvalidRequest => "Invalid request.",
25
UserError::ParseError => "Failed to parse response.",
26
UserError::NetworkError => "Failed to get response.",
27
+ UserError::InvalidCredentials => "Invalid credentials.",
28
}
29
}
30
lib/gem_error_codes/Rakefile
+5
-5
@@ -1,14 +1,14 @@
1
# frozen_string_literal: true
2
3
-require "bundler/gem_tasks"
4
-require "rb_sys/extensiontask"
3
+require 'bundler/gem_tasks'
4
+require 'rb_sys/extensiontask'
5
6
task build: :compile
7
8
-GEMSPEC = Gem::Specification.load("gem_error_codes.gemspec")
8
+GEMSPEC = Gem::Specification.load('gem_error_codes.gemspec')
9
10
-RbSys::ExtensionTask.new("gem_error_codes", GEMSPEC) do |ext|
11
- ext.lib_dir = "lib/gem_error_codes"
10
+RbSys::ExtensionTask.new('gem_error_codes', GEMSPEC) do |ext|
11
+ ext.lib_dir = 'lib/gem_error_codes'
12
end
13
14
task default: :compile
lib/gem_error_codes/ext/gem_error_codes/src/lib.rs
+11
-1
@@ -1,4 +1,4 @@
1
-use crate_error_codes::UserError::UserNotFound;
1
+use crate_error_codes::UserError::{InvalidCredentials, UserNotFound};
2
use magnus::{function, prelude::*, Error, Ruby};
3
4
fn user_not_found() -> i32 {
@@ -8,10 +8,20 @@ fn user_not_found_message() -> String {
8
UserNotFound.error_message().to_string()
9
}
10
11
+fn invalid_credentials() -> i32 {
12
+ InvalidCredentials as i32
13
+}
14
+
15
+fn invalid_credentials_message() -> String {
16
+ InvalidCredentials.error_message().to_string()
17
+}
18
+
19
#[magnus::init]
20
fn init(ruby: &Ruby) -> Result<(), Error> {
21
let module = ruby.define_module("GemErrorCodes")?;
22
module.define_singleton_method("user_not_found", function!(user_not_found, 0))?;
23
module.define_singleton_method("user_not_found_message", function!(user_not_found_message, 0))?;
24
+ module.define_singleton_method("invalid_credentials", function!(invalid_credentials, 0))?;
25
+ module.define_singleton_method("invalid_credentials_message", function!(invalid_credentials_message, 0))?;
26
Ok(())
27
}