WIP
This commit is contained in:
parent
ae400722ba
commit
896ca59ace
@ -24,17 +24,17 @@ modify_table = ["Task", ""]
|
||||
modify_values = [["title", "'$title'"], ["description", "'$description'"], ["completed", "$completed"], ["list_id", "'$list.$id'"]]
|
||||
aggregate_final_json_result = true
|
||||
|
||||
[resolvers.getUser]
|
||||
operation_name = "getUser"
|
||||
[resolvers.createUser]
|
||||
operation_name = "createUser"
|
||||
|
||||
[resolvers.getUser.resolver]
|
||||
command_type = "SQLSelect"
|
||||
[resolvers.createUser.resolver]
|
||||
command_type = "SQLInsert"
|
||||
columns = []
|
||||
tables = [["User", ""]]
|
||||
where_clauses = [["User", "username", "= '$username'"]]
|
||||
tables = []
|
||||
where_clauses = []
|
||||
join_clauses = []
|
||||
modify_table = ["", ""]
|
||||
modify_values = []
|
||||
modify_table = ["User", ""]
|
||||
modify_values = [["username", "'$username'"], ["name", "'$name'"]]
|
||||
aggregate_final_json_result = true
|
||||
|
||||
[resolvers.createList]
|
||||
@ -62,3 +62,16 @@ join_clauses = []
|
||||
modify_table = ["Task", ""]
|
||||
modify_values = [["title", "'$title'"], ["description", "'$description'"], ["completed", "$completed"], ["list_id", "'$list.$id'"], ["user_username", "'$user.$username'"]]
|
||||
aggregate_final_json_result = true
|
||||
|
||||
[resolvers.getUser]
|
||||
operation_name = "getUser"
|
||||
|
||||
[resolvers.getUser.resolver]
|
||||
command_type = "SQLSelect"
|
||||
columns = []
|
||||
tables = [["User", ""]]
|
||||
where_clauses = [["User", "username", "= '$username'"]]
|
||||
join_clauses = []
|
||||
modify_table = ["", ""]
|
||||
modify_values = []
|
||||
aggregate_final_json_result = true
|
||||
|
@ -4,7 +4,7 @@ log_level = "trace"
|
||||
|
||||
[graphql]
|
||||
# path and file name to GraphQL schema file
|
||||
schema_file = "todo5_schema.graphql"
|
||||
schema_file = "todo_schema.graphql"
|
||||
|
||||
[proxy]
|
||||
# host name or IP of basebox DB proxy
|
||||
|
3
bbconf/compile_schema.sh
Executable file
3
bbconf/compile_schema.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# Run basebox installer from the samples/toodo/bbconf directory
|
||||
cargo run --manifest-path ../../../installer/Cargo.toml -- -c install-config.toml
|
@ -20,7 +20,7 @@ acc_aud = "account"
|
||||
|
||||
[graphql]
|
||||
# path and file name to GraphQL schema file
|
||||
schema_file = "todo5_schema.graphql"
|
||||
schema_file = "todo_schema.graphql"
|
||||
# Path and file name of the resolver map file
|
||||
resolver_map_file = "bb_todo_resolvers.toml"
|
||||
# Path and file name of the type map file
|
||||
|
18
bbconf/install-config.toml
Normal file
18
bbconf/install-config.toml
Normal file
@ -0,0 +1,18 @@
|
||||
# Sample toml file; for testing only
|
||||
|
||||
[generic]
|
||||
# the name of the project
|
||||
project_name = "bb_todo"
|
||||
# the folder where the generated files will be placed. If not specifed, the project name will be
|
||||
# used to create a folder by that name in the current directory. Note that the folder must not exist
|
||||
# yet in order to make ensure that an existing installation will not be overwritten by accident.
|
||||
output = "output"
|
||||
|
||||
[log]
|
||||
# log level; can be off, error, warn, info, debug, trace
|
||||
log_level = "info"
|
||||
|
||||
[graphql]
|
||||
schema = "todo_schema.graphql"
|
||||
|
||||
[database]
|
@ -44,6 +44,11 @@ type Query {
|
||||
|
||||
type Mutation {
|
||||
|
||||
createUser(
|
||||
username: String!,
|
||||
name: String!
|
||||
): User @bb_resolver(_type: insert, _object: User, _fields: { username: "$username", name: "$name" })
|
||||
|
||||
createList(
|
||||
title: String!
|
||||
user: User! # username needs to be specified as it's non-nullable
|
@ -1,3 +1,9 @@
|
||||
<!--
|
||||
Component that dispalys authentication related errors.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
<template>
|
||||
|
||||
<div id="error-message">
|
||||
|
@ -1,6 +1,8 @@
|
||||
<!--
|
||||
Dummy component that handles OAuth login callback requests.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
|
@ -1,3 +1,9 @@
|
||||
<!--
|
||||
About component.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
<script setup>
|
||||
import AboutItem from './AboutItem.vue'
|
||||
import DocumentationIcon from './icons/IconDocumentation.vue'
|
||||
|
71
src/components/TodoRoot.vue
Normal file
71
src/components/TodoRoot.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<!--
|
||||
Root component for the Todo app that is displayed if the user is logged in.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {gqlQuery} from "../util/net";
|
||||
import {store} from "../store";
|
||||
|
||||
export default {
|
||||
name: "TodoRoot",
|
||||
|
||||
/** Current state of the component */
|
||||
data() {
|
||||
return {
|
||||
/* array of todo lists currently known */
|
||||
lists: [],
|
||||
/* the name of the list currently being shown */
|
||||
currentList: null,
|
||||
/* tasks of the current list */
|
||||
tasks: [],
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* mounted lifecycle hook.
|
||||
*/
|
||||
mounted() {
|
||||
if (!store.session) {
|
||||
console.error("TodoRoot component must not be loaded if user is not logged in.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load user info and his/her lists and todos */
|
||||
gqlQuery(`query {
|
||||
getUser(username: "${store.session.userName}") {
|
||||
name
|
||||
lists {
|
||||
id
|
||||
title
|
||||
}
|
||||
tasks {
|
||||
id
|
||||
title
|
||||
description
|
||||
list {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}`).then(rspJson => {
|
||||
|
||||
}).catch(err => {
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,3 +1,9 @@
|
||||
<!--
|
||||
Welcome component.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
<script setup>
|
||||
|
||||
import { store} from "../store";
|
||||
|
@ -55,7 +55,7 @@ router.beforeEach(async (to, from) => {
|
||||
});
|
||||
if (!response.ok) {
|
||||
/* redirect to error component */
|
||||
console.error("Failed to get session token: " + response.statusText);
|
||||
console.error("Failed to complete login/get session data: " + response.statusText);
|
||||
return {
|
||||
name: 'oauth-error',
|
||||
query: {
|
||||
|
@ -1,7 +1,8 @@
|
||||
/**
|
||||
* Network related functions.
|
||||
*
|
||||
* markus.thielen@basebox.health
|
||||
* Part of the basebox sample Todo app.
|
||||
* https://basebox.tech
|
||||
*/
|
||||
|
||||
import {store} from "../store";
|
||||
@ -158,7 +159,8 @@ export function gqlQuery(query)
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode object as a query string
|
||||
* Encode simple, unnested objects (dicts) as a query string
|
||||
*
|
||||
* @param obj - a JavaScript object to encode
|
||||
* @returns {string} query string, e.g. "parm1=778&read=all"
|
||||
*/
|
||||
@ -170,3 +172,4 @@ export function objectToQueryString(obj) {
|
||||
}
|
||||
return str.join("&");
|
||||
}
|
||||
|
||||
|
90
src/util/oauth.js
Normal file
90
src/util/oauth.js
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* OAuth specific functions.
|
||||
*
|
||||
* Part of the basebox sample Todo app.
|
||||
* https://basebox.tech
|
||||
*/
|
||||
|
||||
import {store} from "../store";
|
||||
import {gqlQuery} from "./net";
|
||||
|
||||
/**
|
||||
* Handle OAuth callback and complete login process.
|
||||
*
|
||||
* After the user enters her/his credentials at the IdP (Keycloak) login form, she/he
|
||||
* gets redirected to a client URL; this function handles this request.
|
||||
*
|
||||
* This function passes the query string received with the callback to the basebox broker,
|
||||
* which responds with a session information struct (JSON) like this:
|
||||
*
|
||||
* {
|
||||
* "token":"47caa9df-ac89-45a8-8b22-9c0925d6aed0",
|
||||
* "username":"tester",
|
||||
* "first_name":"Fred",
|
||||
* "last_name":"Feuerstein",
|
||||
* "roles":[
|
||||
* "/user"
|
||||
* ],
|
||||
* "claims":{
|
||||
* "groups":[
|
||||
* "/user"
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The session is then stored in app state.
|
||||
*
|
||||
* Then, this function checks if the user is known in the database; since we use Keycloak/OpenID Connect
|
||||
* for user management, the user might be available in Keycloak, but not in the database. So if the user
|
||||
* is not there, it is created.
|
||||
*
|
||||
* @param queryString
|
||||
* @returns {Promise<void>}
|
||||
* @throws Error if the session data cannot be retrieved.
|
||||
*/
|
||||
export async function oauthCallbackHandler(queryString) {
|
||||
|
||||
fetch(`${store.baseboxHost}/oauth/complete-login?${queryString}`, {
|
||||
method: "POST",
|
||||
}).then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to get session data: " + response.statusText);
|
||||
}
|
||||
|
||||
/* Store session data */
|
||||
response.json(
|
||||
).then(rspJson => {
|
||||
store.session = rspJson;
|
||||
store.userName = store.session.first_name ? store.session.first_name : store.session.username;
|
||||
});
|
||||
|
||||
}).catch(e => {
|
||||
throw new Error("Failed to get session data: " + e.toString());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the user on the broker/todo database.
|
||||
*
|
||||
* Since user management is done by Keycloak, which uses its own user database, we must
|
||||
* make sure that out user is known in the app database (basebox broker). After successful
|
||||
* login, this function must be called to do that.
|
||||
*
|
||||
* @param username unique username of new user
|
||||
* @param firstName first name of new user
|
||||
* @param lastName last name of new user
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function createUser(username, firstName, lastName) {
|
||||
|
||||
gqlQuery(`query {
|
||||
createUser(
|
||||
username: "${username}",
|
||||
name: "${firstName} ${lastName}"
|
||||
)`
|
||||
).catch(err => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
@ -1,6 +1,13 @@
|
||||
<!--
|
||||
Home view.
|
||||
|
||||
Part of the basebox sample Todo app.
|
||||
https://basebox.tech
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import { store } from "../store";
|
||||
|
||||
import TodoRoot from "../components/TodoRoot.vue";
|
||||
|
||||
/**
|
||||
* Perform a login.
|
||||
@ -13,11 +20,15 @@ function login() {
|
||||
|
||||
<template>
|
||||
<main>
|
||||
|
||||
<!-- Force user to log in before he/she can see tasks. -->
|
||||
<div v-if="!store.session" id="login-prompt">
|
||||
<p>Your are currently not logged in.</p>
|
||||
<button class="btn btn-primary" @click="login" type="button">Login</button>
|
||||
</div>
|
||||
|
||||
<TodoRoot v-if="store.session" />
|
||||
|
||||
</main>
|
||||
</template>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user