Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Login integration #156

Merged
merged 3 commits into from
Feb 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions backend/src/api/users.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from fastapi import APIRouter
import logging as log
from passlib.hash import bcrypt
from ..api_types import LoginBody, LoginError, ResponseToken
from ..api_types import LoginBody, LoginResponse
from ..db import Database
from ..auth import generateAuthToken

router = APIRouter()


@router.post("/users/login", response_model=ResponseToken | LoginError)
@router.post("/users/login", response_model=LoginResponse | None)
def login(body: LoginBody):
with Database() as db:
try:
Expand All @@ -22,20 +22,20 @@ def login(body: LoginBody):

# Returns "incorrect email/password" message if there is no such account.
if entry_sql is None or len(entry_sql) == 0:
return LoginError.INCORRECT
return LoginResponse(token="", error="Invalid Email or Password")

# Grabs the stored hash and admin.
password_hash, admin = entry_sql[0]

# Returns "incorrect email/password" message if password is incorrect.
if not bcrypt.verify(password, password_hash):
return LoginError.INCORRECT
return LoginResponse(token="", error="Invalid Email or Password")

# Generates the token and returns
token = generateAuthToken(email, admin)
return ResponseToken(token=token)
return LoginResponse(token=token, error="")

except Exception as e:
log.error(e)
# TODO: Return something better than query error
return LoginError.QUERY_ERROR
return LoginResponse(token="", error="Server error.")
10 changes: 2 additions & 8 deletions backend/src/api_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,6 @@ class LoginBody(CamelModel):
password: str


class LoginError(str, enum.Enum):
DEBUG_ACCOUNT = "Debug: Account Not Found"
DEBUG_PASSWORD = "Debug: Incorrect password"
INCORRECT = "Invalid Email or Password"
QUERY_ERROR = "QUERY_ERROR"


class ResponseToken(CamelModel):
class LoginResponse(CamelModel):
token: str
error: str
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@types/cookie": "^0.5.1",
"@types/js-cookie": "^3.0.6",
"autoprefixer": "^10.4.14",
"flowbite": "^2.1.1",
"flowbite-svelte": "^0.44.19",
Expand All @@ -38,6 +39,7 @@
"type": "module",
"dependencies": {
"bibtex": "^0.9.0",
"js-cookie": "^3.0.5",
"marked": "^10.0.0"
}
}
3 changes: 1 addition & 2 deletions frontend/src/openapi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ export type { OpenAPIConfig } from './core/OpenAPI';
export type { EditBody } from './models/EditBody';
export type { HTTPValidationError } from './models/HTTPValidationError';
export type { LoginBody } from './models/LoginBody';
export { LoginError } from './models/LoginError';
export type { LoginResponse } from './models/LoginResponse';
export type { ProteinEntry } from './models/ProteinEntry';
export type { ResponseToken } from './models/ResponseToken';
export type { UploadBody } from './models/UploadBody';
export { UploadError } from './models/UploadError';
export type { ValidationError } from './models/ValidationError';
Expand Down
1 change: 0 additions & 1 deletion frontend/src/openapi/models/EditBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ export type EditBody = {
newContent?: (string | null);
newRefs?: (string | null);
};

1 change: 0 additions & 1 deletion frontend/src/openapi/models/HTTPValidationError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ import type { ValidationError } from './ValidationError';
export type HTTPValidationError = {
detail?: Array<ValidationError>;
};

1 change: 0 additions & 1 deletion frontend/src/openapi/models/LoginBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ export type LoginBody = {
email: string;
password: string;
};

11 changes: 0 additions & 11 deletions frontend/src/openapi/models/LoginError.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */

export type ResponseToken = {
export type LoginResponse = {
token: string;
error: string;
};

1 change: 0 additions & 1 deletion frontend/src/openapi/models/ProteinEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ export type ProteinEntry = {
content?: (string | null);
refs?: (string | null);
};

1 change: 0 additions & 1 deletion frontend/src/openapi/models/UploadBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,3 @@ export type UploadBody = {
refs: string;
pdbFileStr: string;
};

1 change: 0 additions & 1 deletion frontend/src/openapi/models/ValidationError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ export type ValidationError = {
msg: string;
type: string;
};

59 changes: 29 additions & 30 deletions frontend/src/openapi/services/DefaultService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
/* eslint-disable */
import type { EditBody } from '../models/EditBody';
import type { LoginBody } from '../models/LoginBody';
import type { LoginError } from '../models/LoginError';
import type { LoginResponse } from '../models/LoginResponse';
import type { ProteinEntry } from '../models/ProteinEntry';
import type { ResponseToken } from '../models/ResponseToken';
import type { UploadBody } from '../models/UploadBody';
import type { UploadError } from '../models/UploadError';

Expand All @@ -18,13 +17,13 @@ export class DefaultService {

/**
* Login
* @param requestBody
* @returns any Successful Response
* @param requestBody
* @returns LoginResponse Successful Response
* @throws ApiError
*/
public static login(
requestBody: LoginBody,
): CancelablePromise<(ResponseToken | LoginError)> {
requestBody: LoginBody,
): CancelablePromise<LoginResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/users/login',
Expand All @@ -38,13 +37,13 @@ export class DefaultService {

/**
* Get Pdb File
* @param proteinName
* @param proteinName
* @returns any Successful Response
* @throws ApiError
*/
public static getPdbFile(
proteinName: string,
): CancelablePromise<any> {
proteinName: string,
): CancelablePromise<any> {
return __request(OpenAPI, {
method: 'GET',
url: '/pdb/{protein_name}',
Expand All @@ -59,13 +58,13 @@ export class DefaultService {

/**
* Get Fasta File
* @param proteinName
* @param proteinName
* @returns any Successful Response
* @throws ApiError
*/
public static getFastaFile(
proteinName: string,
): CancelablePromise<any> {
proteinName: string,
): CancelablePromise<any> {
return __request(OpenAPI, {
method: 'GET',
url: '/fasta/{protein_name}',
Expand All @@ -81,7 +80,7 @@ export class DefaultService {
/**
* Get All Entries
* Gets all protein entries from the database
* Returns: list[ProteinEntry] if found | None if not found
* Returns: list[ProteinEntry] if found | None if not found
* @returns any Successful Response
* @throws ApiError
*/
Expand All @@ -95,14 +94,14 @@ export class DefaultService {
/**
* Search Entries
* Gets a list of protein entries by a search string
* Returns: list[ProteinEntry] if found | None if not found
* @param proteinName
* Returns: list[ProteinEntry] if found | None if not found
* @param proteinName
* @returns any Successful Response
* @throws ApiError
*/
public static searchEntries(
proteinName: string,
): CancelablePromise<(Array<ProteinEntry> | null)> {
proteinName: string,
): CancelablePromise<(Array<ProteinEntry> | null)> {
return __request(OpenAPI, {
method: 'GET',
url: '/search-entries/{protein_name}',
Expand All @@ -118,14 +117,14 @@ export class DefaultService {
/**
* Get Protein Entry
* Get a single protein entry by its id
* Returns: ProteinEntry if found | None if not found
* @param proteinName
* Returns: ProteinEntry if found | None if not found
* @param proteinName
* @returns any Successful Response
* @throws ApiError
*/
public static getProteinEntry(
proteinName: string,
): CancelablePromise<(ProteinEntry | null)> {
proteinName: string,
): CancelablePromise<(ProteinEntry | null)> {
return __request(OpenAPI, {
method: 'GET',
url: '/protein-entry/{protein_name}',
Expand All @@ -140,13 +139,13 @@ export class DefaultService {

/**
* Delete Protein Entry
* @param proteinName
* @param proteinName
* @returns any Successful Response
* @throws ApiError
*/
public static deleteProteinEntry(
proteinName: string,
): CancelablePromise<any> {
proteinName: string,
): CancelablePromise<any> {
return __request(OpenAPI, {
method: 'DELETE',
url: '/protein-entry/{protein_name}',
Expand All @@ -161,13 +160,13 @@ export class DefaultService {

/**
* Upload Protein Entry
* @param requestBody
* @param requestBody
* @returns any Successful Response
* @throws ApiError
*/
public static uploadProteinEntry(
requestBody: UploadBody,
): CancelablePromise<(UploadError | null)> {
requestBody: UploadBody,
): CancelablePromise<(UploadError | null)> {
return __request(OpenAPI, {
method: 'POST',
url: '/protein-upload',
Expand All @@ -181,13 +180,13 @@ export class DefaultService {

/**
* Edit Protein Entry
* @param requestBody
* @param requestBody
* @returns any Successful Response
* @throws ApiError
*/
public static editProteinEntry(
requestBody: EditBody,
): CancelablePromise<(UploadError | null)> {
requestBody: EditBody,
): CancelablePromise<(UploadError | null)> {
return __request(OpenAPI, {
method: 'PUT',
url: '/protein-edit',
Expand Down
52 changes: 43 additions & 9 deletions frontend/src/routes/login/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,30 +1,64 @@
<script lang="ts">
import { Backend, type LoginResponse } from "$lib/backend";
import { Button, Label, Input } from "flowbite-svelte";
import Cookies from "js-cookie";

let username: string = "";
let email: string = "";
let password: string = "";
$: formValid = username.length > 0 && password.length > 0;
$: formValid = email.length > 0 && password.length > 0;

let error = false;

let token = "";
/**
* Gets run on button "Login" or form submit (pressing enter)
* @todo add login logic with tokens and making a request to the backend
*/
function submitForm() {
let result: LoginResponse | null=null
async function submitForm() {
if (!formValid) return;

console.log("submitted");
console.table({ username, password });
try {
// Attempting to get a valid authentication token from the API
result = await Backend.login({
email,
password
})

if (result==null) {
// If result is null, log to console. Don't expect this would happen.
console.log("Response is null")

} else if (result['error'] != "") {
// User entered wrong username or password, or account doesn't exist.
// @todo Display this error message to the user.
console.log("Response received. Error: " + result['error'])

} else if (result['token'] != "") {
// User entered the correct username / password and got a result.
// @todo Store this in a cookie.
console.log("Response received. Token: " + result['token'])
Cookies.set('auth', result['token'])

} else {
// User got a result, but both fields are null. This should never happen.
console.log("Unexpected edge cage regarding user authentication.")
}

} catch (e){
console.log(e)
}
}
</script>

<form on:submit={submitForm} class="flex gap-5 flex-col">
<div>
<Label for="username">Username</Label>
<Label for="email">Email</Label>
<Input
id="username"
id="email"
style="width: 300px;"
bind:value={username}
placeholder="Enter your username..."
bind:value={email}
placeholder="Enter your email..."
/>
</div>

Expand Down
10 changes: 10 additions & 0 deletions frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.3.tgz#2be19e759a3dd18c79f9f436bd7363556c1a73dd"
integrity sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==

"@types/js-cookie@^3.0.6":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.6.tgz#a04ca19e877687bd449f5ad37d33b104b71fdf95"
integrity sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==

"@types/json-schema@^7.0.6":
version "7.0.14"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1"
Expand Down Expand Up @@ -964,6 +969,11 @@ jiti@^1.19.1:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==

js-cookie@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==

js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
Expand Down
Loading