Retrieve existing profile for welcome page (#2)
This commit is contained in:
parent
daece3eab1
commit
2f84821d11
|
@ -96,3 +96,39 @@ module Citizens =
|
||||||
|> Sql.parameters [ "@id", (CitizenId.toString >> Sql.string) citizenId ]
|
|> Sql.parameters [ "@id", (CitizenId.toString >> Sql.string) citizenId ]
|
||||||
|> Sql.executeRowAsync fromReader
|
|> Sql.executeRowAsync fromReader
|
||||||
|> noneIfNotFound
|
|> noneIfNotFound
|
||||||
|
|
||||||
|
|
||||||
|
/// Functions for manipulating employment profiles
|
||||||
|
module Profiles =
|
||||||
|
|
||||||
|
/// Create a Profile from a row of data
|
||||||
|
let private fromReader (read: RowReader) =
|
||||||
|
match (read.string >> CitizenId.tryParse) "citizen_id" with
|
||||||
|
| Ok citizenId ->
|
||||||
|
match (read.string >> ContinentId.tryParse) "continent_id" with
|
||||||
|
| Ok continentId -> {
|
||||||
|
citizenId = citizenId
|
||||||
|
seekingEmployment = read.bool "seeking_employment"
|
||||||
|
isPublic = read.bool "is_public"
|
||||||
|
continent = { id = continentId; name = read.string "continent_name" }
|
||||||
|
region = read.string "region"
|
||||||
|
remoteWork = read.bool "remote_work"
|
||||||
|
fullTime = read.bool "full_time"
|
||||||
|
biography = (read.string >> MarkdownString) "biography"
|
||||||
|
lastUpdatedOn = (read.int64 >> Millis) "last_updated_on"
|
||||||
|
experience = (read.stringOrNone >> Option.map MarkdownString) "experience"
|
||||||
|
}
|
||||||
|
| Error err -> failwith err
|
||||||
|
| Error err -> failwith err
|
||||||
|
|
||||||
|
/// Try to find an employment profile for the given citizen ID
|
||||||
|
let tryFind citizenId =
|
||||||
|
db ()
|
||||||
|
|> Sql.query
|
||||||
|
"""SELECT p.*, c.name AS continent_name
|
||||||
|
FROM profile p
|
||||||
|
INNER JOIN continent c ON p.continent_id = c.id
|
||||||
|
WHERE citizen_id = @id"""
|
||||||
|
|> Sql.parameters [ "@id", (CitizenId.toString >> Sql.string) citizenId ]
|
||||||
|
|> Sql.executeRowAsync fromReader
|
||||||
|
|> noneIfNotFound
|
||||||
|
|
|
@ -185,7 +185,7 @@ type Profile = {
|
||||||
/// Whether information from this profile should appear in the public anonymous list of available skills
|
/// Whether information from this profile should appear in the public anonymous list of available skills
|
||||||
isPublic : bool
|
isPublic : bool
|
||||||
/// The continent on which the user is seeking employment
|
/// The continent on which the user is seeking employment
|
||||||
continentId : Continent
|
continent : Continent
|
||||||
/// The region within that continent where the user would prefer to work
|
/// The region within that continent where the user would prefer to work
|
||||||
region : string
|
region : string
|
||||||
/// Whether the user is looking for remote work
|
/// Whether the user is looking for remote work
|
||||||
|
|
|
@ -121,7 +121,24 @@ module Citizen =
|
||||||
| Error msg -> return! Error.error (exn msg) "Could not authenticate with NAS" ctx
|
| Error msg -> return! Error.error (exn msg) "Could not authenticate with NAS" ctx
|
||||||
| Error exn -> return! Error.error exn "Token not received" ctx
|
| Error exn -> return! Error.error exn "Token not received" ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// /api/profile route handlers
|
||||||
|
module Profile =
|
||||||
|
|
||||||
|
/// GET: /api/profile
|
||||||
|
let get citizenId : WebPart =
|
||||||
|
authorizedUser
|
||||||
|
>=> fun ctx -> async {
|
||||||
|
match (match citizenId with "" -> Ok (currentCitizenId ctx) | _ -> CitizenId.tryParse citizenId) with
|
||||||
|
| Ok citId ->
|
||||||
|
match! Profiles.tryFind citId with
|
||||||
|
| Ok (Some profile) -> return! json profile ctx
|
||||||
|
| Ok None -> return! Error.notFound ctx
|
||||||
|
| Error exn -> return! Error.error exn "Cannot retrieve profile" ctx
|
||||||
|
| Error _ -> return! Error.notFound ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open Suave.Filters
|
open Suave.Filters
|
||||||
|
|
||||||
|
@ -129,7 +146,9 @@ open Suave.Filters
|
||||||
let webApp =
|
let webApp =
|
||||||
choose
|
choose
|
||||||
[ GET >=> choose
|
[ GET >=> choose
|
||||||
[ path "/" >=> Vue.app
|
[ pathScan "/api/profile/%s" Profile.get
|
||||||
|
path "/api/profile" >=> Profile.get ""
|
||||||
|
path "/" >=> Vue.app
|
||||||
Files.browse "wwwroot/"
|
Files.browse "wwwroot/"
|
||||||
]
|
]
|
||||||
// PUT >=> choose
|
// PUT >=> choose
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Profile } from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jobs, Jobs, Jobs API interface
|
* Jobs, Jobs, Jobs API interface
|
||||||
|
*
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @version 1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** The base URL for the Jobs, Jobs, Jobs API */
|
/** The base URL for the Jobs, Jobs, Jobs API */
|
||||||
|
@ -59,7 +65,7 @@ export async function doRequest(url: string, method?: string, payload?: string)
|
||||||
if (method === 'POST' && payload) options.body = payload
|
if (method === 'POST' && payload) options.body = payload
|
||||||
const actualUrl = (options.method === 'GET' && payload) ? `url?${payload}` : url
|
const actualUrl = (options.method === 'GET' && payload) ? `url?${payload}` : url
|
||||||
const resp = await fetch(actualUrl, options)
|
const resp = await fetch(actualUrl, options)
|
||||||
if (resp.ok) return resp
|
if (resp.ok || resp.status === 404) return resp
|
||||||
throw new Error(`Error executing API request: ${resp.status} ~ ${resp.statusText}`)
|
throw new Error(`Error executing API request: ${resp.status} ~ ${resp.statusText}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,3 +81,17 @@ export async function jjjAuthorize(nasToken: string): Promise<boolean> {
|
||||||
jwt.token = jjjToken.accessToken
|
jwt.token = jjjToken.accessToken
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the employment profile for the current user.
|
||||||
|
*
|
||||||
|
* @returns The profile if it is found; undefined otherwise
|
||||||
|
*/
|
||||||
|
export async function userProfile(): Promise<Profile | undefined> {
|
||||||
|
const resp = await doRequest(`${API_URL}/profile`)
|
||||||
|
if (resp.status === 404) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const profile = await resp.json()
|
||||||
|
return profile as Profile
|
||||||
|
}
|
||||||
|
|
52
src/jobs-jobs-jobs/src/api/types.ts
Normal file
52
src/jobs-jobs-jobs/src/api/types.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* Client-side Type Definitions for Jobs, Jobs, Jobs.
|
||||||
|
*
|
||||||
|
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||||
|
* @version 1
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A continent (one of the 7).
|
||||||
|
*/
|
||||||
|
export interface Continent {
|
||||||
|
/** The ID of the continent */
|
||||||
|
id: string
|
||||||
|
|
||||||
|
/** The name of the continent */
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user's employment profile.
|
||||||
|
*/
|
||||||
|
export interface Profile {
|
||||||
|
/** The ID of the user to whom the profile applies */
|
||||||
|
citizenId: string
|
||||||
|
|
||||||
|
/** Whether this user is actively seeking employment */
|
||||||
|
seekingEmployment: boolean
|
||||||
|
|
||||||
|
/** Whether information from this profile should appear in the public anonymous list of available skills */
|
||||||
|
isPublic: boolean
|
||||||
|
|
||||||
|
/** The continent on which the user is seeking employment */
|
||||||
|
continent: Continent
|
||||||
|
|
||||||
|
/** The region within that continent where the user would prefer to work */
|
||||||
|
region: string
|
||||||
|
|
||||||
|
/** Whether the user is looking for remote work */
|
||||||
|
remoteWork: boolean
|
||||||
|
|
||||||
|
/** Whether the user is looking for full-time work */
|
||||||
|
fullTime: boolean
|
||||||
|
|
||||||
|
/** The user's professional biography */
|
||||||
|
biography: string
|
||||||
|
|
||||||
|
/** When this profile was last updated */
|
||||||
|
lastUpdatedOn: number
|
||||||
|
|
||||||
|
/** The user's experience */
|
||||||
|
experience?: string
|
||||||
|
}
|
|
@ -1,3 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div>Welcome</div>
|
<div>
|
||||||
|
<p>Welcome!</p>
|
||||||
|
<p>Profile Established: <strong><span v-if="profile?.value">Yes</span><span v-else>No</span></strong></p>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { onBeforeMount, ref } from 'vue'
|
||||||
|
|
||||||
|
import { userProfile } from '@/api'
|
||||||
|
import { Profile } from '@/api/types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const profile = ref<Profile | undefined>(undefined)
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
profile.value = await userProfile()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
profile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user