mirror of
https://github.com/abhinavxd/libredesk.git
synced 2025-10-23 05:11:57 +00:00
PUSH COMMITS
This commit is contained in:
35
cmd/auth.go
35
cmd/auth.go
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/abhinavxd/artemis/internal/envelope"
|
||||
"github.com/abhinavxd/artemis/internal/stringutil"
|
||||
|
||||
@@ -8,35 +10,52 @@ import (
|
||||
"github.com/zerodha/fastglue"
|
||||
)
|
||||
|
||||
// handleOIDCLogin initializes an OIDC request and redirects to the OIDC provider for login.
|
||||
// handleOIDCLogin redirects to the OIDC provider for login.
|
||||
func handleOIDCLogin(r *fastglue.Request) error {
|
||||
var (
|
||||
app = r.Context.(*App)
|
||||
app = r.Context.(*App)
|
||||
providerID, err = strconv.Atoi(r.RequestCtx.UserValue("id").(string))
|
||||
)
|
||||
if err != nil {
|
||||
app.lo.Error("error parsing provider id", "error", err)
|
||||
return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error parsing provider id.", nil, envelope.GeneralError)
|
||||
}
|
||||
|
||||
// TODO: Figure csrf thing out
|
||||
state, err := stringutil.RandomAlNumString(30)
|
||||
if err != nil {
|
||||
app.lo.Error("error generating random string", "error", err)
|
||||
return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Something went wrong, Please try again.", nil, envelope.GeneralError)
|
||||
}
|
||||
authURL := app.auth.LoginURL(state)
|
||||
|
||||
authURL, err := app.auth.LoginURL(providerID, state)
|
||||
if err != nil {
|
||||
return sendErrorEnvelope(r, err)
|
||||
}
|
||||
|
||||
return r.Redirect(authURL, fasthttp.StatusFound, nil, "")
|
||||
}
|
||||
|
||||
// handleOIDCCallback receives the redirect callback from the OIDC provider and completes the handshake.
|
||||
func handleOIDCCallback(r *fastglue.Request) error {
|
||||
var (
|
||||
app = r.Context.(*App)
|
||||
code = string(r.RequestCtx.QueryArgs().Peek("code"))
|
||||
state = string(r.RequestCtx.QueryArgs().Peek("state"))
|
||||
app = r.Context.(*App)
|
||||
code = string(r.RequestCtx.QueryArgs().Peek("code"))
|
||||
state = string(r.RequestCtx.QueryArgs().Peek("state"))
|
||||
providerID, err = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("id")))
|
||||
)
|
||||
if err != nil {
|
||||
app.lo.Error("error parsing provider id", "error", err)
|
||||
return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error parsing provider id.", nil, envelope.GeneralError)
|
||||
}
|
||||
|
||||
_, claims, err := app.auth.ExchangeOIDCToken(r.RequestCtx, code)
|
||||
_, claims, err := app.auth.ExchangeOIDCToken(r.RequestCtx, providerID, code)
|
||||
if err != nil {
|
||||
app.lo.Error("error exchanging oidc token", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get user by e-mail received from OIDC.
|
||||
// Get user by e-mail received.
|
||||
user, err := app.user.GetByEmail(claims.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) {
|
||||
g.POST("/api/login", handleLogin)
|
||||
g.GET("/api/logout", handleLogout)
|
||||
g.GET("/api/oidc/login", handleOIDCLogin)
|
||||
g.GET("/api/oidc/{id}/login", handleOIDCLogin)
|
||||
g.GET("/api/oidc/finish", handleOIDCCallback)
|
||||
|
||||
// Health check.
|
||||
|
35
cmd/init.go
35
cmd/init.go
@@ -269,7 +269,7 @@ func initMedia(db *sqlx.DB) *media.Manager {
|
||||
case "localfs":
|
||||
store, err = localfs.New(localfs.Opts{
|
||||
UploadURI: "/uploads",
|
||||
UploadPath: filepath.Clean(ko.String("app.localfs.upload_path")),
|
||||
UploadPath: filepath.Clean(ko.String("upload.localfs.upload_path")),
|
||||
RootURL: ko.String("app.root_url"),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -411,16 +411,31 @@ func registerInboxes(mgr *inbox.Manager, store inbox.MessageStore) {
|
||||
}
|
||||
}
|
||||
|
||||
func initAuth(rd *redis.Client) *auth.Auth {
|
||||
lo := initLogger("auth")
|
||||
func initAuth(o *oidc.Manager, rd *redis.Client) *auth.Auth {
|
||||
var lo = initLogger("auth")
|
||||
|
||||
oidc, err := o.GetAll()
|
||||
if err != nil {
|
||||
log.Fatalf("error initializing auth: %v", err)
|
||||
}
|
||||
|
||||
var providers = make([]auth.Provider, 0, len(oidc))
|
||||
for _, o := range oidc {
|
||||
if o.Disabled {
|
||||
continue
|
||||
}
|
||||
providers = append(providers, auth.Provider{
|
||||
ID: o.ID,
|
||||
Provider: o.Provider,
|
||||
ProviderURL: o.ProviderURL,
|
||||
RedirectURL: o.RedirectURI,
|
||||
ClientID: o.ClientID,
|
||||
ClientSecret: o.ClientSecret,
|
||||
})
|
||||
}
|
||||
|
||||
a, err := auth.New(auth.Config{
|
||||
OIDC: auth.OIDCConfig{
|
||||
Enabled: true,
|
||||
ProviderURL: "https://accounts.google.com",
|
||||
RedirectURL: "http://localhost:5173/auth/oidc/finish",
|
||||
ClientID: "a",
|
||||
ClientSecret: "a",
|
||||
},
|
||||
Providers: providers,
|
||||
}, rd, lo)
|
||||
if err != nil {
|
||||
log.Fatalf("error initializing auth: %v", err)
|
||||
|
@@ -83,6 +83,8 @@ func main() {
|
||||
i18n = initI18n(fs)
|
||||
lo = initLogger("artemis")
|
||||
rdb = initRedis()
|
||||
oidc = initOIDC(db)
|
||||
auth = initAuth(oidc, rdb)
|
||||
template = initTemplate(db)
|
||||
media = initMedia(db)
|
||||
contact = initContact(db)
|
||||
@@ -119,7 +121,7 @@ func main() {
|
||||
var app = &App{
|
||||
lo: lo,
|
||||
rdb: rdb,
|
||||
auth: initAuth(rdb),
|
||||
auth: auth,
|
||||
fs: fs,
|
||||
i18n: i18n,
|
||||
media: media,
|
||||
@@ -131,7 +133,7 @@ func main() {
|
||||
tmpl: template,
|
||||
conversation: conversation,
|
||||
automation: automation,
|
||||
oidc: initOIDC(db),
|
||||
oidc: oidc,
|
||||
role: initRole(db),
|
||||
constant: initConstants(),
|
||||
tag: initTags(db),
|
||||
|
29
cmd/oidc.go
29
cmd/oidc.go
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/abhinavxd/artemis/internal/envelope"
|
||||
@@ -9,32 +10,38 @@ import (
|
||||
"github.com/zerodha/fastglue"
|
||||
)
|
||||
|
||||
// handleGetAllOIDC returns all oidc records
|
||||
const (
|
||||
redirectURI = "/api/oidc/finish?id=%d"
|
||||
)
|
||||
|
||||
// handleGetAllOIDC returns all OIDC records
|
||||
func handleGetAllOIDC(r *fastglue.Request) error {
|
||||
var (
|
||||
app = r.Context.(*App)
|
||||
)
|
||||
o, err := app.oidc.GetAll()
|
||||
app := r.Context.(*App)
|
||||
|
||||
out, err := app.oidc.GetAll()
|
||||
if err != nil {
|
||||
return sendErrorEnvelope(r, err)
|
||||
}
|
||||
return r.SendEnvelope(o)
|
||||
return r.SendEnvelope(out)
|
||||
}
|
||||
|
||||
// handleGetOIDC returns an OIDC record by id.
|
||||
func handleGetOIDC(r *fastglue.Request) error {
|
||||
var (
|
||||
app = r.Context.(*App)
|
||||
)
|
||||
app := r.Context.(*App)
|
||||
|
||||
id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string))
|
||||
if err != nil || id == 0 {
|
||||
if err != nil || id <= 0 {
|
||||
return r.SendErrorEnvelope(fasthttp.StatusBadRequest,
|
||||
"Invalid oidc `id`", nil, envelope.InputError)
|
||||
"Invalid OIDC `id`", nil, envelope.InputError)
|
||||
}
|
||||
|
||||
o, err := app.oidc.Get(id)
|
||||
if err != nil {
|
||||
return sendErrorEnvelope(r, err)
|
||||
}
|
||||
|
||||
o.RedirectURI = fmt.Sprintf("%s%s", app.constant.AppBaseURL, fmt.Sprintf(redirectURI, o.ID))
|
||||
|
||||
return r.SendEnvelope(o)
|
||||
}
|
||||
|
||||
|
@@ -54,7 +54,7 @@
|
||||
"textarea": "^0.3.0",
|
||||
"tiptap-extension-resize-image": "^1.1.5",
|
||||
"vee-validate": "^4.13.2",
|
||||
"vue": "^3.4.15",
|
||||
"vue": "^3.4.37",
|
||||
"vue-draggable-resizable": "^3.0.0",
|
||||
"vue-i18n": "9",
|
||||
"vue-letter": "^0.2.0",
|
||||
|
BIN
frontend/public/images/github-logo.png
Normal file
BIN
frontend/public/images/github-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
BIN
frontend/public/images/google-logo.png
Normal file
BIN
frontend/public/images/google-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@@ -7,7 +7,7 @@
|
||||
<ResizablePanel id="resize-panel-1" collapsible :default-size="10" :collapsed-size="1" :min-size="7"
|
||||
:max-size="20" :class="cn(isCollapsed && 'min-w-[50px] transition-all duration-200 ease-in-out')"
|
||||
@expand="toggleNav(false)" @collapse="toggleNav(true)">
|
||||
<NavBar :is-collapsed="isCollapsed" :links="navLinks" />
|
||||
<NavBar :is-collapsed="isCollapsed" :links="navLinks" :bottom-links="bottomLinks" />
|
||||
</ResizablePanel>
|
||||
<ResizableHandle id="resize-handle-1" />
|
||||
<ResizablePanel id="resize-panel-2">
|
||||
@@ -70,6 +70,16 @@ const allNavLinks = ref([
|
||||
permission: 'admin:get',
|
||||
},
|
||||
]);
|
||||
|
||||
const bottomLinks = ref(
|
||||
[
|
||||
{
|
||||
to: '/logout',
|
||||
icon: 'lucide:log-out',
|
||||
title: 'Logout'
|
||||
}
|
||||
]
|
||||
)
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
|
||||
|
@@ -8,7 +8,8 @@ import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from '@/comp
|
||||
|
||||
defineProps({
|
||||
isCollapsed: Boolean,
|
||||
links: Array
|
||||
links: Array,
|
||||
bottomLinks: Array
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
@@ -25,7 +26,7 @@ const getButtonVariant = (to) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :data-collapsed="isCollapsed" class="group flex flex-col gap-4 py-2 data-[collapsed=true]:py-2">
|
||||
<div :data-collapsed="isCollapsed" class="group flex flex-col gap-4 py-2 data-[collapsed=true]:py-2 h-full">
|
||||
<nav class="grid gap-1 px-2 group-[[data-collapsed=true]]:justify-center group-[[data-collapsed=true]]:px-2">
|
||||
<template v-for="(link, index) of links">
|
||||
<!-- Collapsed -->
|
||||
@@ -74,5 +75,30 @@ const getButtonVariant = (to) => {
|
||||
</router-link>
|
||||
</template>
|
||||
</nav>
|
||||
|
||||
<!-- Bottom Links -->
|
||||
<div class="mt-auto px-2">
|
||||
<template v-for="(bottomLink, index) in bottomLinks" :key="`bottom-${index}`">
|
||||
<TooltipProvider :delay-duration="10">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<router-link :to="bottomLink.to" :class="cn(
|
||||
buttonVariants({ variant: getButtonVariant(bottomLink.to), size: isCollapsed ? 'icon' : 'sm' }),
|
||||
bottomLink.variant === getButtonVariant(bottomLink.to) &&
|
||||
'dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white',
|
||||
'justify-start'
|
||||
)">
|
||||
<Icon :icon="bottomLink.icon" class="mr-2 size-5" v-if="!isCollapsed" />
|
||||
<span v-if="!isCollapsed">{{ bottomLink.title }}</span>
|
||||
<Icon :icon="bottomLink.icon" class="size-5 mx-auto" v-else />
|
||||
</router-link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" class="flex items-center gap-4">
|
||||
{{ bottomLink.title }}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex flex-col space-y-5">
|
||||
<div>
|
||||
<div class="space-y-1">
|
||||
<span class="sub-title">Public avatar</span>
|
||||
<p class="text-muted-foreground text-xs">Change your avatar here.</p>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="border rounded-lg">
|
||||
<div class="box rounded-lg">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||
|
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div class="box border p-5 space-y-5">
|
||||
<div class="box border p-5 space-y-5 rounded-lg">
|
||||
<div class="space-y-5">
|
||||
<div v-for="(rule, index) in ruleGroup.rules" :key="rule" class="space-y-5">
|
||||
<div v-if="index > 0">
|
||||
|
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="flex flex-col box border p-5 space-y-2">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-col box px-5 py-6 rounded-lg justify-center">
|
||||
<div class="flex justify-between space-y-3">
|
||||
<div>
|
||||
<span class="sub-title flex space-x-3 items-center">
|
||||
<span class="sub-title space-x-3 flex justify-center items-center">
|
||||
<div class="text-base">
|
||||
{{ rule.name }}
|
||||
</div>
|
||||
<div>
|
||||
<Badge v-if="!rule.disabled" class="text-[10px] py-0 px-1">Enabled</Badge>
|
||||
<Badge v-else class="text-[10px] py-0 px-1" variant="secondary">Disabled</Badge>
|
||||
<div class="mb-1">
|
||||
<Badge v-if="!rule.disabled">Enabled</Badge>
|
||||
<Badge v-else variant="secondary">Disabled</Badge>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
@@ -36,7 +36,7 @@
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
<p class="text-sm-muted">
|
||||
{{ rule.description }}
|
||||
</p>
|
||||
</div>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="space-y-5">
|
||||
<div>
|
||||
<p class="text-muted-foreground text-sm">Rules that run when a new conversation is created</p>
|
||||
<p class="text-sm-muted">Rules that run when a new conversation is created</p>
|
||||
</div>
|
||||
<div v-if="showRuleList" class="space-y-5">
|
||||
<RuleList v-for="rule in rules" :key="rule.name" :rule="rule" @delete-rule="deleteRule" @toggle-rule="toggleRule"/>
|
||||
|
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div
|
||||
class="max-w-sm overflow-hidden box rounded-lg px-8 py-5 transition-shadow duration-170 cursor-pointer hover:bg-muted"
|
||||
class="box rounded-lg px-8 py-4 transition-shadow duration-170 cursor-pointer hover:bg-muted"
|
||||
@click="handleClick">
|
||||
<div class="flex items-center mb-4">
|
||||
<component :is="icon" size="17" class="mr-2" />
|
||||
<p class="text-xl">{{ title }}</p>
|
||||
<component :is="icon" size="16" class="mr-2" />
|
||||
<p class="text-lg">{{ title }}</p>
|
||||
</div>
|
||||
<p class="text-xs-muted">{{ subTitle }}</p>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-col space-y-1">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<span class="text-2xl">{{ title }}</span>
|
||||
<p class="text-xs-muted">{{ description }}</p>
|
||||
</div>
|
||||
|
@@ -2,23 +2,25 @@
|
||||
<div class="mb-5">
|
||||
<CustomBreadcrumb :links="breadcrumbLinks" />
|
||||
</div>
|
||||
<OIDCForm :initial-values="oidc" :submitForm="submitForm" />
|
||||
<OIDCForm :initial-values="oidc" :submitForm="submitForm" :isNewForm=isNewForm />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import api from '@/api'
|
||||
import OIDCForm from './OIDCForm.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { CustomBreadcrumb } from '@/components/ui/breadcrumb'
|
||||
|
||||
const oidc = ref({})
|
||||
const oidc = ref({
|
||||
"provider": "Google"
|
||||
})
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
required: false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -35,6 +37,10 @@ const breadCrumLabel = () => {
|
||||
return props.id ? "Edit" : 'New';
|
||||
}
|
||||
|
||||
const isNewForm = computed(() => {
|
||||
return props.id ? false : true;
|
||||
})
|
||||
|
||||
const breadcrumbLinks = [
|
||||
{ path: '/admin/oidc', label: 'OIDC' },
|
||||
{ path: '#', label: breadCrumLabel() }
|
||||
|
@@ -1,10 +1,48 @@
|
||||
<template>
|
||||
<form @submit="onSubmit" class="w-2/3 space-y-6">
|
||||
|
||||
<FormField v-slot="{ componentField }" name="provider">
|
||||
<FormItem>
|
||||
<FormLabel>Provider</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a provider" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="Google">
|
||||
Google
|
||||
</SelectItem>
|
||||
<SelectItem value="Github">
|
||||
Github
|
||||
</SelectItem>
|
||||
<SelectItem value="Custom">
|
||||
Custom
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Google" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="provider_url">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Provider URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="url" placeholder="Provider URL" v-bind="componentField" />
|
||||
<Input type="text" placeholder="Provider URL" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -30,12 +68,30 @@
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="redirect_uri">
|
||||
<FormField v-slot="{ componentField }" name="redirect_uri" v-if="!isNewForm">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Redirect URI</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="url" placeholder="Redirect URI" v-bind="componentField" />
|
||||
<Input type="text" placeholder="Redirect URI" v-bind="componentField" readonly />
|
||||
<span class="absolute end-0 inset-y-0 flex items-center justify-center px-2 cursor-pointer">
|
||||
<Copy size="16" />
|
||||
</span>
|
||||
</FormControl>
|
||||
<FormDescription>Set this URI for callback.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
|
||||
<FormField name="disabled" v-slot="{ value, handleChange }" v-if="!isNewForm">
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox :checked="value" @update:checked="handleChange" />
|
||||
<Label>Disable</Label>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormDescription></FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -50,15 +106,27 @@ import { Button } from '@/components/ui/button'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { oidcLoginFormSchema } from './formSchema.js'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { vAutoAnimate } from '@formkit/auto-animate/vue'
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage
|
||||
FormMessage,
|
||||
FormDescription,
|
||||
} from '@/components/ui/form'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Copy } from 'lucide-vue-next';
|
||||
|
||||
const props = defineProps({
|
||||
initialValues: {
|
||||
@@ -74,6 +142,9 @@ const props = defineProps({
|
||||
required: false,
|
||||
default: () => 'Save'
|
||||
},
|
||||
isNewForm: {
|
||||
type: Boolean
|
||||
}
|
||||
})
|
||||
|
||||
const form = useForm({
|
||||
@@ -90,6 +161,6 @@ watch(
|
||||
(newValues) => {
|
||||
form.setValues(newValues)
|
||||
},
|
||||
{ deep: true }
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
</script>
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex justify-between mb-5">
|
||||
<div class="flex justify-between mb-5">
|
||||
<PageHeader title="OIDC" description="Manage OpenID Connect configurations" />
|
||||
<div>
|
||||
<Button size="sm" @click="navigateToAddOIDC">New OIDC</Button>
|
||||
@@ -17,16 +17,23 @@ import DataTable from '@/components/admin/DataTable.vue'
|
||||
import { columns } from '@/components/admin/oidc/dataTableColumns.js'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
import PageHeader from '../common/PageHeader.vue'
|
||||
import api from '@/api'
|
||||
|
||||
const oidc = ref([])
|
||||
const router = useRouter()
|
||||
const emit = useEmitter()
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
fetchAll()
|
||||
emit.on('refresh-inbox-list', fetchAll)
|
||||
})
|
||||
|
||||
const fetchAll = async () => {
|
||||
const resp = await api.getAllOIDC()
|
||||
oidc.value = resp.data.data
|
||||
})
|
||||
}
|
||||
|
||||
const navigateToAddOIDC = () => {
|
||||
router.push("/admin/oidc/new")
|
||||
|
@@ -3,14 +3,36 @@ import dropdown from './dataTableDropdown.vue'
|
||||
import { format } from 'date-fns'
|
||||
|
||||
export const columns = [
|
||||
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Name')
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('name'))
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'provider',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Provider')
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('name'))
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('provider'))
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'disabled',
|
||||
header: () => h('div', { class: 'text-center' }, 'Enabled'),
|
||||
cell: ({ row }) => {
|
||||
const disabled = row.getValue('disabled')
|
||||
return h('div', { class: 'text-center' }, [
|
||||
h('input', {
|
||||
type: 'checkbox',
|
||||
checked: !disabled,
|
||||
disabled: true
|
||||
})
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@@ -9,8 +9,10 @@ import {
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useRouter } from 'vue-router'
|
||||
import api from '@/api'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
|
||||
const router = useRouter()
|
||||
const emit = useEmitter()
|
||||
|
||||
const props = defineProps({
|
||||
role: {
|
||||
@@ -28,6 +30,7 @@ function edit (id) {
|
||||
|
||||
async function deleteOIDC (id) {
|
||||
await api.deleteOIDC(id)
|
||||
emit.emit('refresh-inbox-list')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@@ -1,6 +1,14 @@
|
||||
import * as z from 'zod'
|
||||
|
||||
export const oidcLoginFormSchema = z.object({
|
||||
disabled: z
|
||||
.boolean().optional(),
|
||||
name: z
|
||||
.string({
|
||||
required_error: 'Name is required.'
|
||||
}),
|
||||
provider: z
|
||||
.string().optional(),
|
||||
provider_url: z
|
||||
.string({
|
||||
required_error: 'Provider URL is required.'
|
||||
@@ -16,11 +24,5 @@ export const oidcLoginFormSchema = z.object({
|
||||
.string({
|
||||
required_error: 'Client Secret is required.'
|
||||
}),
|
||||
redirect_uri: z
|
||||
.string({
|
||||
required_error: 'Redirect URI is required.'
|
||||
})
|
||||
.url({
|
||||
message: 'Redirect URI must be a valid URL.'
|
||||
})
|
||||
redirect_uri: z.string().readonly().optional(),
|
||||
})
|
||||
|
@@ -38,7 +38,6 @@
|
||||
</FormField>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button type="submit" size="sm">{{ submitLabel }}</Button>
|
||||
</form>
|
||||
</template>
|
||||
@@ -118,7 +117,6 @@ const form = useForm({
|
||||
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
values.permissions = selectedPermissions.value
|
||||
console.log("submitting ", values)
|
||||
props.submitForm(values)
|
||||
})
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import api from '@/api'
|
||||
const { toast } = useToast()
|
||||
const breadcrumbLinks = [
|
||||
{ path: '/admin/teams', label: 'Teams' },
|
||||
{ path: '/admin/teams/users', label: 'Users'},
|
||||
{ path: '/admin/teams/users', label: 'Users' },
|
||||
{ path: '#', label: 'Add user' }
|
||||
]
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="mb-5">
|
||||
<CustomBreadcrumb :links="breadcrumbLinks" />
|
||||
</div>
|
||||
<UserForm :initial-values="user" :submitForm="submitForm" />
|
||||
<UserForm :initialValues="user" :submitForm="submitForm" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<form @submit.prevent="onSubmit" class="w-2/3 space-y-6">
|
||||
<form @submit.prevent="onSubmit" class="space-y-6">
|
||||
<FormField v-slot="{ field }" name="first_name">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>First name</FormLabel>
|
||||
@@ -29,23 +29,23 @@
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField name="teams" v-slot="{ field }">
|
||||
<FormField name="teams" v-slot="{ componentField }">
|
||||
<FormItem>
|
||||
<FormLabel>Select teams</FormLabel>
|
||||
<FormControl>
|
||||
<SelectTag :initialValue="field.value" v-model="selectedTeamNames" :items="teamNames"
|
||||
placeHolder="Select teams"></SelectTag>
|
||||
<SelectTag v-model="componentField.modelValue" :items="teamNames" placeHolder="Select teams"></SelectTag>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField name="roles" v-slot="{ field }">
|
||||
<FormField name="roles" v-slot="{ componentField }">
|
||||
<FormItem>
|
||||
<FormLabel>Select roles</FormLabel>
|
||||
<FormControl>
|
||||
<SelectTag :initialValue="field.value" v-model="selectedRoleNames" :items="roleNames"
|
||||
placeHolder="Select roles"></SelectTag>
|
||||
<SelectTag v-model="componentField.modelValue" :items="roleNames" placeHolder="Select roles"></SelectTag>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
@@ -81,9 +81,6 @@ import {
|
||||
import { Input } from '@/components/ui/input'
|
||||
import api from '@/api'
|
||||
|
||||
|
||||
const selectedRoleNames = ref([])
|
||||
const selectedTeamNames = ref([])
|
||||
const teams = ref([])
|
||||
const roles = ref([])
|
||||
|
||||
@@ -133,7 +130,6 @@ const form = useForm({
|
||||
})
|
||||
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
console.log('submitting ', values)
|
||||
props.submitForm(values)
|
||||
})
|
||||
|
||||
@@ -142,15 +138,7 @@ watch(
|
||||
() => props.initialValues,
|
||||
(newValues) => {
|
||||
form.setValues(newValues)
|
||||
if (newValues) {
|
||||
if (newValues.roles)
|
||||
selectedRoleNames.value = newValues.roles
|
||||
|
||||
if (newValues.teams)
|
||||
selectedTeamNames.value = newValues.teams
|
||||
}
|
||||
|
||||
},
|
||||
{ immediate: true }
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
</script>
|
@@ -114,8 +114,7 @@
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>S3 backend URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="url" placeholder="https://ap-south-1.s3.amazonaws.com" v-bind="componentField"
|
||||
defaultValue="https://ap-south-1.s3.amazonaws.com" />
|
||||
<Input type="url" placeholder="https://ap-south-1.s3.amazonaws.com" v-bind="componentField"/>
|
||||
</FormControl>
|
||||
<FormDescription>Only change if using a custom S3 compatible backend like Minio.</FormDescription>
|
||||
<FormMessage />
|
||||
|
@@ -1,249 +0,0 @@
|
||||
<template>
|
||||
<div v-if="formProvider === 's3'">
|
||||
<form @submit="onS3FormSubmit" class="w-2/3 space-y-6">
|
||||
<FormField v-slot="{ componentField }" name="provider">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Provider</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField" v-model="componentField.modelValue"
|
||||
@update:modelValue="handleProviderUpdate">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a provider" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="s3">
|
||||
S3
|
||||
</SelectItem>
|
||||
<SelectItem value="localfs">
|
||||
Local filesystem
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="region">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Region</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="ap-south-1" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="access_key">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>AWS access key</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="AWS access key" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="access_secret">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>AWS access secret</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="AWS access secret" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="bucket_type">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Bucket type</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField" v-model="componentField.modelValue">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select bucket type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="public">
|
||||
Public
|
||||
</SelectItem>
|
||||
<SelectItem value="private">
|
||||
Private
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="bucket">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Bucket</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Bucket" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="bucket_path">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Bucket path</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Bucket path" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="upload_expiry">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Upload expiry</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="24h" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormDescription>Only applicable for private buckets.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="url">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>S3 backend URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="url" placeholder="https://ap-south-1.s3.amazonaws.com" v-bind="componentField"
|
||||
defaultValue="https://ap-south-1.s3.amazonaws.com" />
|
||||
</FormControl>
|
||||
<FormDescription>Only change if using a custom S3 compatible backend like Minio.</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<Button type="submit" size="sm"> {{ submitLabel }} </Button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<form @submit="onLocalFsSubmit" class="w-2/3 space-y-6">
|
||||
<FormField v-slot="{ componentField }" name="provider">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Provider</FormLabel>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField" v-model="componentField.modelValue"
|
||||
@update:modelValue="handleProviderUpdate">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a provider" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="s3">
|
||||
S3
|
||||
</SelectItem>
|
||||
<SelectItem value="localfs">
|
||||
Local filesystem
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField }" name="upload_path">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Upload path</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="/home/ubuntu/uploads" v-bind="componentField" />
|
||||
</FormControl>
|
||||
<FormDescription> Path to the directory where files will be uploaded. </FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
<Button type="submit" size="sm"> {{ submitLabel }} </Button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { s3FormSchema, localFsFormSchema } from './formSchema.js'
|
||||
import { vAutoAnimate } from '@formkit/auto-animate/vue'
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
FormDescription
|
||||
} from '@/components/ui/form'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Input } from '@/components/ui/input'
|
||||
|
||||
const props = defineProps({
|
||||
initialValues: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
submitForm: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
submitLabel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => 'Submit'
|
||||
},
|
||||
})
|
||||
|
||||
const s3Form = useForm({
|
||||
validationSchema: toTypedSchema(s3FormSchema),
|
||||
})
|
||||
|
||||
const localFsForm = useForm({
|
||||
validationSchema: toTypedSchema(localFsFormSchema),
|
||||
})
|
||||
|
||||
const formProvider = ref(props.initialValues?.provider || 's3')
|
||||
|
||||
const onS3FormSubmit = s3Form.handleSubmit((values) => {
|
||||
console.log("v ", values)
|
||||
props.submitForm(values)
|
||||
})
|
||||
|
||||
const onLocalFsSubmit = localFsForm.handleSubmit((values) => {
|
||||
props.submitForm(values)
|
||||
})
|
||||
|
||||
const handleProviderUpdate = (value) => {
|
||||
formProvider.value = value
|
||||
}
|
||||
|
||||
// Watch for changes in initialValues and update the form.
|
||||
watch(
|
||||
() => props.initialValues,
|
||||
(newValues) => {
|
||||
formProvider.value = newValues.provider
|
||||
if (newValues.provider === 's3') {
|
||||
s3Form.setValues(newValues)
|
||||
} else {
|
||||
localFsForm.setValues(newValues)
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
</script>
|
@@ -55,7 +55,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<Error :errorMessage="conversationStore.conversations.errorMessage"></Error>
|
||||
<EmptyList v-if="emptyConversations"></EmptyList>
|
||||
|
||||
<div class="h-screen overflow-y-scroll pb-[180px] flex flex-col">
|
||||
|
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<BarChart :data="data" index="status" :categories="['Low', 'Medium', 'High']" :show-grid-line="true" :y-formatter="(tick) => {
|
||||
return tick
|
||||
}" :margin="{ top: 0, bottom: 0, left: 0, right: 0 }" />
|
||||
<BarChart :data="data" index="status" :categories="['Low', 'Medium', 'High']" :show-grid-line="true"
|
||||
:margin="{ top: 0, bottom: 0, left: 0, right: 0 }" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
@@ -39,7 +39,6 @@ const emitter = useEmitter()
|
||||
|
||||
const scrollToBottom = () => {
|
||||
setTimeout(() => {
|
||||
console.log("Scrolling bottom")
|
||||
const thread = threadEl.value
|
||||
if (thread) {
|
||||
thread.scrollTop = thread.scrollHeight
|
||||
|
@@ -8,7 +8,7 @@
|
||||
</TagsInputItem>
|
||||
</div>
|
||||
|
||||
<ComboboxRoot v-model="filteredItems" v-model:open="isOpen" @onUpdate:searchTerm="searchTerm" class="w-full">
|
||||
<ComboboxRoot v-model:open="isOpen" class="w-full">
|
||||
<ComboboxAnchor as-child>
|
||||
<ComboboxInput :placeholder="placeHolder" as-child>
|
||||
<TagsInputInput class="w-full px-3" :class="selectedItems.length > 0 ? 'mt-2' : ''"
|
||||
@@ -57,7 +57,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const selectedItems = defineModel();
|
||||
const selectedItems = defineModel({ default: [] });
|
||||
const isOpen = ref(false);
|
||||
const searchTerm = ref('');
|
||||
const dropdownRef = ref(null);
|
||||
|
@@ -226,6 +226,11 @@ export const useConversationStore = defineStore('conversation', () => {
|
||||
}
|
||||
} catch (error) {
|
||||
conversations.errorMessage = handleHTTPError(error).message;
|
||||
toast({
|
||||
title: 'Could not fetch conversations.',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message,
|
||||
});
|
||||
} finally {
|
||||
conversations.loading = false;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="page-content w-11/12">
|
||||
<div class="page-content w-10/12">
|
||||
<div class="flex flex-col space-y-6">
|
||||
<div>
|
||||
<span class="font-medium text-2xl space-y-1" v-if="userStore.getFullName">
|
||||
@@ -79,7 +79,7 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { format, subWeeks, subMonths, subYears, formatISO } from 'date-fns'
|
||||
import { format } from 'date-fns'
|
||||
import api from '@/api';
|
||||
import { useToast } from '@/components/ui/toast/use-toast'
|
||||
|
||||
@@ -94,13 +94,14 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
|
||||
|
||||
const { toast } = useToast()
|
||||
const userStore = useUserStore()
|
||||
const cardCounts = ref({})
|
||||
const chartData = ref({})
|
||||
const filter = ref("me")
|
||||
const filter = useLocalStorage('dashboard_filter', 'me');
|
||||
const barChartFilter = ref("last_week")
|
||||
const lineChartFilter = ref("last_week")
|
||||
const agentCountCardsLabels = {
|
||||
@@ -110,12 +111,6 @@ const agentCountCardsLabels = {
|
||||
awaiting_response_count: "Awaiting Response",
|
||||
};
|
||||
|
||||
const chartFilters = {
|
||||
last_week: getLastWeekRange(),
|
||||
last_month: getLastMonthRange(),
|
||||
last_year: getLastYearRange(),
|
||||
};
|
||||
``
|
||||
onMounted(() => {
|
||||
getCardStats()
|
||||
getDashboardCharts()
|
||||
@@ -132,7 +127,6 @@ const onDashboardFilterChange = (v) => {
|
||||
}
|
||||
|
||||
const onLineChartFilterChange = (v) => {
|
||||
console.log("chart filter -> ", chartFilters)
|
||||
lineChartFilter.value = v
|
||||
}
|
||||
|
||||
@@ -140,33 +134,6 @@ const onBarChartFilterChange = (v) => {
|
||||
barChartFilter.value = v
|
||||
}
|
||||
|
||||
function getLastWeekRange () {
|
||||
const today = new Date();
|
||||
const lastWeekStart = subWeeks(today, 1);
|
||||
return {
|
||||
start: formatISO(lastWeekStart, { representation: 'date' }),
|
||||
end: formatISO(today, { representation: 'date' }),
|
||||
};
|
||||
}
|
||||
|
||||
function getLastMonthRange () {
|
||||
const today = new Date();
|
||||
const lastMonthStart = subMonths(today, 1);
|
||||
return {
|
||||
start: formatISO(lastMonthStart, { representation: 'date' }),
|
||||
end: formatISO(today, { representation: 'date' }),
|
||||
};
|
||||
}
|
||||
|
||||
function getLastYearRange () {
|
||||
const today = new Date();
|
||||
const lastYearStart = subYears(today, 1);
|
||||
return {
|
||||
start: formatISO(lastYearStart, { representation: 'date' }),
|
||||
end: formatISO(today, { representation: 'date' }),
|
||||
};
|
||||
}
|
||||
|
||||
const getCardStats = () => {
|
||||
let apiCall;
|
||||
switch (filter.value) {
|
||||
|
@@ -9,10 +9,10 @@
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="grid gap-4">
|
||||
<div class="grid grid-cols-1 gap-6" v-for="oidcProvider in oidcProviders"
|
||||
:key="oidcProvider.id">
|
||||
<Button variant="outline" @click.prevent="redirectToOIDCLogin">
|
||||
<img :src="oidcProvider.logo_url" width="15" class="mr-2"/>
|
||||
<div v-for="oidcProvider in enabledOIDCProviders" :key="oidcProvider.id"
|
||||
class="grid grid-cols-1 gap-6">
|
||||
<Button variant="outline" @click.prevent="redirectToOIDC(oidcProvider)">
|
||||
<img :src="oidcProvider.logo_url" width="15" class="mr-2" />
|
||||
{{ oidcProvider.name }}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -52,7 +52,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { handleHTTPError } from '@/utils/http'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
@@ -82,9 +82,9 @@ const loginForm = ref({
|
||||
const userStore = useUserStore()
|
||||
const oidcProviders = ref([])
|
||||
|
||||
const redirectToOIDCLogin = () => {
|
||||
window.location.href = "/auth/oidc/login"
|
||||
}
|
||||
const redirectToOIDC = (provider) => {
|
||||
window.location.href = `/api/oidc/${provider.id}/login`
|
||||
};
|
||||
|
||||
const loginAction = () => {
|
||||
errorMessage.value = ""
|
||||
@@ -114,4 +114,9 @@ onMounted(async () => {
|
||||
const resp = await api.getAllOIDC()
|
||||
oidcProviders.value = resp.data.data
|
||||
})
|
||||
|
||||
const enabledOIDCProviders = computed(() => {
|
||||
return oidcProviders.value.filter(provider => !provider.disabled);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
@@ -635,6 +635,21 @@
|
||||
dependencies:
|
||||
"@floating-ui/utils" "^0.2.0"
|
||||
|
||||
"@floating-ui/core@^1.6.0":
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.7.tgz#7602367795a390ff0662efd1c7ae8ca74e75fb12"
|
||||
integrity sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==
|
||||
dependencies:
|
||||
"@floating-ui/utils" "^0.2.7"
|
||||
|
||||
"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.6.7":
|
||||
version "1.6.10"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.10.tgz#b74c32f34a50336c86dcf1f1c845cf3a39e26d6f"
|
||||
integrity sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.6.0"
|
||||
"@floating-ui/utils" "^0.2.7"
|
||||
|
||||
"@floating-ui/dom@^1.6.1", "@floating-ui/dom@^1.6.5":
|
||||
version "1.6.5"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.5.tgz#323f065c003f1d3ecf0ff16d2c2c4d38979f4cb9"
|
||||
@@ -648,6 +663,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5"
|
||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||
|
||||
"@floating-ui/utils@^0.2.7":
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.7.tgz#d0ece53ce99ab5a8e37ebdfe5e32452a2bfc073e"
|
||||
integrity sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==
|
||||
|
||||
"@floating-ui/vue@^1.0.6":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-1.0.6.tgz#31860a12f1135d19554c232d99c5bab631c5c576"
|
||||
@@ -657,6 +677,15 @@
|
||||
"@floating-ui/utils" "^0.2.1"
|
||||
vue-demi ">=0.13.0"
|
||||
|
||||
"@floating-ui/vue@^1.1.0":
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-1.1.4.tgz#1dd6905a58baaa9a84c44c2cf28e281f715957a1"
|
||||
integrity sha512-ammH7T3vyCx7pmm9OF19Wc42zrGnUw0QvLoidgypWsCLJMtGXEwY7paYIHO+K+oLC3mbWpzIHzeTVienYenlNg==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.0.0"
|
||||
"@floating-ui/utils" "^0.2.7"
|
||||
vue-demi ">=0.13.0"
|
||||
|
||||
"@formkit/auto-animate@^0.8.2":
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@formkit/auto-animate/-/auto-animate-0.8.2.tgz#24a56e816159fd5585405dcee6bb992f81c27585"
|
||||
@@ -1241,6 +1270,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.5.0.tgz#108208d0f1d75271300bc5560cf9a85a1fa01e89"
|
||||
integrity sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg==
|
||||
|
||||
"@tanstack/virtual-core@3.8.6":
|
||||
version "3.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.8.6.tgz#ccecf84099a9a0e9732b4f17bf021b82f215d15e"
|
||||
integrity sha512-UJeU4SBrx3hqULNzJ3oC0kgJ5miIAg+FwomxMTlQNxob6ppTInifANHd9ukETvzdzxr6zt3CjQ0rttQpVjbt6Q==
|
||||
|
||||
"@tanstack/vue-table@^8.19.2":
|
||||
version "8.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/vue-table/-/vue-table-8.19.2.tgz#909f63a225788757f62a7b7fa4568da6349b9a0f"
|
||||
@@ -1255,6 +1289,13 @@
|
||||
dependencies:
|
||||
"@tanstack/virtual-core" "3.5.0"
|
||||
|
||||
"@tanstack/vue-virtual@^3.8.1":
|
||||
version "3.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@tanstack/vue-virtual/-/vue-virtual-3.8.6.tgz#c37a11ee8a03f04eaeaca7523eaa3963098e0728"
|
||||
integrity sha512-nWwmlFuxChPM6bWEwKOyBBYVrQmvSKSArXhbvX2IyVTpuif9UZiBEvIXnftpCEGRvAGSe7lE1coXHk8g2qmwtQ==
|
||||
dependencies:
|
||||
"@tanstack/virtual-core" "3.8.6"
|
||||
|
||||
"@tiptap/core@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.4.0.tgz#6f8eee8beb5b89363582366b201ccc4798ac98a9"
|
||||
@@ -1909,17 +1950,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37"
|
||||
integrity sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==
|
||||
|
||||
"@vue/compiler-core@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.27.tgz#e69060f4b61429fe57976aa5872cfa21389e4d91"
|
||||
integrity sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.24.4"
|
||||
"@vue/shared" "3.4.27"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-core@3.4.31", "@vue/compiler-core@^3.0.0":
|
||||
version "3.4.31"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.31.tgz#b51a76f1b30e9b5eba0553264dff0f171aedb7c6"
|
||||
@@ -1931,13 +1961,16 @@
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-dom@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz#d51d35f40d00ce235d7afc6ad8b09dfd92b1cc1c"
|
||||
integrity sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==
|
||||
"@vue/compiler-core@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.4.37.tgz#55db3900e09424c65c39111a05a3c6e698f371e3"
|
||||
integrity sha512-ZDDT/KiLKuCRXyzWecNzC5vTcubGz4LECAtfGPENpo0nrmqJHwuWtRLxk/Sb9RAKtR9iFflFycbkjkY+W/PZUQ==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
"@babel/parser" "^7.24.7"
|
||||
"@vue/shared" "3.4.37"
|
||||
entities "^5.0.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-dom@3.4.31", "@vue/compiler-dom@^3.4.27":
|
||||
version "3.4.31"
|
||||
@@ -1947,19 +1980,27 @@
|
||||
"@vue/compiler-core" "3.4.31"
|
||||
"@vue/shared" "3.4.31"
|
||||
|
||||
"@vue/compiler-sfc@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz#399cac1b75c6737bf5440dc9cf3c385bb2959701"
|
||||
integrity sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==
|
||||
"@vue/compiler-dom@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.37.tgz#a1fcf79e287cb828545082ff1afa8630480a3044"
|
||||
integrity sha512-rIiSmL3YrntvgYV84rekAtU/xfogMUJIclUMeIKEtVBFngOL3IeZHhsH3UaFEgB5iFGpj6IW+8YuM/2Up+vVag==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.24.4"
|
||||
"@vue/compiler-core" "3.4.27"
|
||||
"@vue/compiler-dom" "3.4.27"
|
||||
"@vue/compiler-ssr" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
"@vue/compiler-core" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
"@vue/compiler-sfc@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.37.tgz#8afaf1a86cb849422c765d4369ba1e85fffe0234"
|
||||
integrity sha512-vCfetdas40Wk9aK/WWf8XcVESffsbNkBQwS5t13Y/PcfqKfIwJX2gF+82th6dOpnpbptNMlMjAny80li7TaCIg==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.24.7"
|
||||
"@vue/compiler-core" "3.4.37"
|
||||
"@vue/compiler-dom" "3.4.37"
|
||||
"@vue/compiler-ssr" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.30.10"
|
||||
postcss "^8.4.38"
|
||||
postcss "^8.4.40"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-sfc@^3.4", "@vue/compiler-sfc@^3.4.27":
|
||||
@@ -1977,14 +2018,6 @@
|
||||
postcss "^8.4.38"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-ssr@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz#2a8ecfef1cf448b09be633901a9c020360472e3d"
|
||||
integrity sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
|
||||
"@vue/compiler-ssr@3.4.31":
|
||||
version "3.4.31"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.31.tgz#f62ffecdf15bacb883d0099780cf9a1e3654bfc4"
|
||||
@@ -1993,6 +2026,14 @@
|
||||
"@vue/compiler-dom" "3.4.31"
|
||||
"@vue/shared" "3.4.31"
|
||||
|
||||
"@vue/compiler-ssr@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.37.tgz#b75e1c76c3184f86fa9f0ba4d61d13bc6afcbf8a"
|
||||
integrity sha512-TyAgYBWrHlFrt4qpdACh8e9Ms6C/AZQ6A6xLJaWrCL8GCX5DxMzxyeFAEMfU/VFr4tylHm+a2NpfJpcd7+20XA==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
"@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.5.1":
|
||||
version "6.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.1.tgz#7c14346383751d9f6ad4bea0963245b30220ef83"
|
||||
@@ -2018,7 +2059,22 @@
|
||||
dependencies:
|
||||
"@vue/shared" "3.4.27"
|
||||
|
||||
"@vue/runtime-core@3.4.27", "@vue/runtime-core@^3.4.15":
|
||||
"@vue/reactivity@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.37.tgz#5a199563eaab51ed9f94ddf0a82f9179bcc01676"
|
||||
integrity sha512-UmdKXGx0BZ5kkxPqQr3PK3tElz6adTey4307NzZ3whZu19i5VavYal7u2FfOmAzlcDVgE8+X0HZ2LxLb/jgbYw==
|
||||
dependencies:
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
"@vue/runtime-core@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.37.tgz#3fe734a666db7842bea4185a13f7697a2102b719"
|
||||
integrity sha512-MNjrVoLV/sirHZoD7QAilU1Ifs7m/KJv4/84QVbE6nyAZGQNVOa1HGxaOzp9YqCG+GpLt1hNDC4RbH+KtanV7w==
|
||||
dependencies:
|
||||
"@vue/reactivity" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
"@vue/runtime-core@^3.4.15":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.27.tgz#1b6e1d71e4604ba7442dd25ed22e4a1fc6adbbda"
|
||||
integrity sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==
|
||||
@@ -2026,22 +2082,23 @@
|
||||
"@vue/reactivity" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
|
||||
"@vue/runtime-dom@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz#fe8d1ce9bbe8921d5dd0ad5c10df0e04ef7a5ee7"
|
||||
integrity sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==
|
||||
"@vue/runtime-dom@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.37.tgz#219f84577027103de6ddc71351d8237c7c16adac"
|
||||
integrity sha512-Mg2EwgGZqtwKrqdL/FKMF2NEaOHuH+Ks9TQn3DHKyX//hQTYOun+7Tqp1eo0P4Ds+SjltZshOSRq6VsU0baaNg==
|
||||
dependencies:
|
||||
"@vue/runtime-core" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
"@vue/reactivity" "3.4.37"
|
||||
"@vue/runtime-core" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
csstype "^3.1.3"
|
||||
|
||||
"@vue/server-renderer@3.4.27":
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.27.tgz#3306176f37e648ba665f97dda3ce705687be63d2"
|
||||
integrity sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==
|
||||
"@vue/server-renderer@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.37.tgz#d341425bb5395a3f6ed70572ea5c3edefab92f28"
|
||||
integrity sha512-jZ5FAHDR2KBq2FsRUJW6GKDOAG9lUTX8aBEGq4Vf6B/35I9fPce66BornuwmqmKgfiSlecwuOb6oeoamYMohkg==
|
||||
dependencies:
|
||||
"@vue/compiler-ssr" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
"@vue/compiler-ssr" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
"@vue/shared@3.4.27":
|
||||
version "3.4.27"
|
||||
@@ -2053,6 +2110,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.31.tgz#af9981f57def2c3f080c14bf219314fc0dc808a0"
|
||||
integrity sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==
|
||||
|
||||
"@vue/shared@3.4.37":
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.37.tgz#4f4c08a2e73da512a77b47165cf59ffbc1b5ade8"
|
||||
integrity sha512-nIh8P2fc3DflG8+5Uw8PT/1i17ccFn0xxN/5oE9RfV5SVnd7G0XEFRwakrnNFE/jlS95fpGXDVG5zDETS26nmg==
|
||||
|
||||
"@vuedx/template-ast-types@0.7.1":
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@vuedx/template-ast-types/-/template-ast-types-0.7.1.tgz#ccc75786a4fe1d1910f6c8d93d150d44ee1dabdc"
|
||||
@@ -2060,7 +2122,7 @@
|
||||
dependencies:
|
||||
"@vue/compiler-core" "^3.0.0"
|
||||
|
||||
"@vueuse/core@^10.11.1":
|
||||
"@vueuse/core@^10.11.0", "@vueuse/core@^10.11.1":
|
||||
version "10.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-10.11.1.tgz#15d2c0b6448d2212235b23a7ba29c27173e0c2c6"
|
||||
integrity sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==
|
||||
@@ -2090,7 +2152,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-10.9.0.tgz#769a1a9db65daac15cf98084cbf7819ed3758620"
|
||||
integrity sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==
|
||||
|
||||
"@vueuse/shared@10.11.1":
|
||||
"@vueuse/shared@10.11.1", "@vueuse/shared@^10.11.0":
|
||||
version "10.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-10.11.1.tgz#62b84e3118ae6e1f3ff38f4fbe71b0c5d0f10938"
|
||||
integrity sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==
|
||||
@@ -2325,7 +2387,7 @@ argparse@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
aria-hidden@^1.2.3:
|
||||
aria-hidden@^1.2.3, aria-hidden@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522"
|
||||
integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==
|
||||
@@ -3828,6 +3890,11 @@ entities@^4.4.0, entities@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
|
||||
entities@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-5.0.0.tgz#b2ab51fe40d995817979ec79dd621154c3c0f62b"
|
||||
integrity sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==
|
||||
|
||||
env-paths@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
|
||||
@@ -6178,7 +6245,7 @@ nanoid@^3.3.7:
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
|
||||
integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
|
||||
|
||||
nanoid@^5.0.6:
|
||||
nanoid@^5.0.6, nanoid@^5.0.7:
|
||||
version "5.0.7"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.7.tgz#6452e8c5a816861fd9d2b898399f7e5fd6944cc6"
|
||||
integrity sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==
|
||||
@@ -7184,6 +7251,15 @@ postcss@^8.4.23, postcss@^8.4.38:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
postcss@^8.4.40:
|
||||
version "8.4.41"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681"
|
||||
integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==
|
||||
dependencies:
|
||||
nanoid "^3.3.7"
|
||||
picocolors "^1.0.1"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
potpack@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
|
||||
@@ -7615,22 +7691,22 @@ radix-vue@^1.7.3:
|
||||
fast-deep-equal "^3.1.3"
|
||||
nanoid "^5.0.6"
|
||||
|
||||
radix-vue@^1.8.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/radix-vue/-/radix-vue-1.8.1.tgz#5e0cb08a1540b7d3ad5c21e39f5ebe5bd735f826"
|
||||
integrity sha512-DFyUt2vc/89tpSHiJvv7Qb/Qs8zVxq2g7q4kuuDV46fmDmSC3mnV3hdSAYruU7k/KvoDpS3sd99kLGRtuG63Rw==
|
||||
radix-vue@latest:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/radix-vue/-/radix-vue-1.9.3.tgz#4fa171a570a366730114bbd065531b2ce6037359"
|
||||
integrity sha512-9pewcgzghM+B+FO1h9mMsZa/csVH6hElpN1sqmG4/qoeieiDG0i4nhMjS7p2UOz11EEdVm7eLandHSPyx7hYhg==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.6.5"
|
||||
"@floating-ui/vue" "^1.0.6"
|
||||
"@floating-ui/dom" "^1.6.7"
|
||||
"@floating-ui/vue" "^1.1.0"
|
||||
"@internationalized/date" "^3.5.4"
|
||||
"@internationalized/number" "^3.5.3"
|
||||
"@tanstack/vue-virtual" "^3.5.0"
|
||||
"@vueuse/core" "^10.5.0"
|
||||
"@vueuse/shared" "^10.5.0"
|
||||
aria-hidden "^1.2.3"
|
||||
"@tanstack/vue-virtual" "^3.8.1"
|
||||
"@vueuse/core" "^10.11.0"
|
||||
"@vueuse/shared" "^10.11.0"
|
||||
aria-hidden "^1.2.4"
|
||||
defu "^6.1.4"
|
||||
fast-deep-equal "^3.1.3"
|
||||
nanoid "^5.0.6"
|
||||
nanoid "^5.0.7"
|
||||
|
||||
rc9@^2.1.2:
|
||||
version "2.1.2"
|
||||
@@ -9226,16 +9302,16 @@ vue-router@^4.2.5:
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.5.1"
|
||||
|
||||
vue@^3.4.15:
|
||||
version "3.4.27"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.27.tgz#40b7d929d3e53f427f7f5945386234d2854cc2a1"
|
||||
integrity sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==
|
||||
vue@^3.4.37:
|
||||
version "3.4.37"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.37.tgz#64ce0eeb8de16a29fb74e504777ee8c0c1cf229e"
|
||||
integrity sha512-3vXvNfkKTBsSJ7JP+LyR7GBuwQuckbWvuwAid3xbqK9ppsKt/DUvfqgZ48fgOLEfpy1IacL5f8QhUVl77RaI7A==
|
||||
dependencies:
|
||||
"@vue/compiler-dom" "3.4.27"
|
||||
"@vue/compiler-sfc" "3.4.27"
|
||||
"@vue/runtime-dom" "3.4.27"
|
||||
"@vue/server-renderer" "3.4.27"
|
||||
"@vue/shared" "3.4.27"
|
||||
"@vue/compiler-dom" "3.4.37"
|
||||
"@vue/compiler-sfc" "3.4.37"
|
||||
"@vue/runtime-dom" "3.4.37"
|
||||
"@vue/server-renderer" "3.4.37"
|
||||
"@vue/shared" "3.4.37"
|
||||
|
||||
w3c-keyname@^2.2.0:
|
||||
version "2.2.8"
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/abhinavxd/artemis/internal/envelope"
|
||||
"github.com/abhinavxd/artemis/internal/user/models"
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/redis/go-redis/v9"
|
||||
@@ -26,42 +27,51 @@ type OIDCclaim struct {
|
||||
Picture string `json:"picture"`
|
||||
}
|
||||
|
||||
type OIDCConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
ProviderURL string `json:"provider_url"`
|
||||
RedirectURL string `json:"redirect_url"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"client_secret"`
|
||||
type Provider struct {
|
||||
ID int
|
||||
Provider string
|
||||
ProviderURL string
|
||||
RedirectURL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
OIDC OIDCConfig
|
||||
Providers []Provider
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
cfg Config
|
||||
oauthCfg oauth2.Config
|
||||
verifier *oidc.IDTokenVerifier
|
||||
sess *simplesessions.Manager
|
||||
lo *logf.Logger
|
||||
cfg Config
|
||||
oauthCfgs map[int]oauth2.Config
|
||||
verifiers map[int]*oidc.IDTokenVerifier
|
||||
sess *simplesessions.Manager
|
||||
logger *logf.Logger
|
||||
}
|
||||
|
||||
// New inits a OIDC configuration
|
||||
// New initializes an OIDC configuration for multiple providers.
|
||||
func New(cfg Config, rd *redis.Client, logger *logf.Logger) (*Auth, error) {
|
||||
provider, err := oidc.NewProvider(context.Background(), cfg.OIDC.ProviderURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oauthCfgs := make(map[int]oauth2.Config)
|
||||
verifiers := make(map[int]*oidc.IDTokenVerifier)
|
||||
|
||||
oauthCfg := oauth2.Config{
|
||||
ClientID: cfg.OIDC.ClientID,
|
||||
ClientSecret: cfg.OIDC.ClientSecret,
|
||||
Endpoint: provider.Endpoint(),
|
||||
RedirectURL: cfg.OIDC.RedirectURL,
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||
}
|
||||
for _, provider := range cfg.Providers {
|
||||
oidcProv, err := oidc.NewProvider(context.Background(), provider.ProviderURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initializing `%s` oidc login: %v", provider.Provider, err)
|
||||
}
|
||||
|
||||
verifier := provider.Verifier(&oidc.Config{ClientID: cfg.OIDC.ClientID})
|
||||
oauthCfg := oauth2.Config{
|
||||
ClientID: provider.ClientID,
|
||||
ClientSecret: provider.ClientSecret,
|
||||
Endpoint: oidcProv.Endpoint(),
|
||||
RedirectURL: provider.RedirectURL,
|
||||
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
|
||||
}
|
||||
|
||||
verifier := oidcProv.Verifier(&oidc.Config{ClientID: provider.ClientID})
|
||||
|
||||
oauthCfgs[provider.ID] = oauthCfg
|
||||
verifiers[provider.ID] = verifier
|
||||
}
|
||||
|
||||
sess := simplesessions.New(simplesessions.Options{
|
||||
EnableAutoCreate: false,
|
||||
@@ -72,27 +82,42 @@ func New(cfg Config, rd *redis.Client, logger *logf.Logger) (*Auth, error) {
|
||||
MaxAge: time.Hour * 12,
|
||||
},
|
||||
})
|
||||
|
||||
st := sessredisstore.New(context.TODO(), rd)
|
||||
sess.UseStore(st)
|
||||
sess.SetCookieHooks(simpleSessGetCookieCB, simpleSessSetCookieCB)
|
||||
|
||||
return &Auth{
|
||||
cfg: cfg,
|
||||
oauthCfg: oauthCfg,
|
||||
verifier: verifier,
|
||||
lo: logger,
|
||||
sess: sess,
|
||||
cfg: cfg,
|
||||
oauthCfgs: oauthCfgs,
|
||||
verifiers: verifiers,
|
||||
sess: sess,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoginURL
|
||||
func (a *Auth) LoginURL(state string) string {
|
||||
return a.oauthCfg.AuthCodeURL(state)
|
||||
// LoginURL generates a login URL for a specific provider using its ID.
|
||||
func (a *Auth) LoginURL(providerID int, state string) (string, error) {
|
||||
oauthCfg, ok := a.oauthCfgs[providerID]
|
||||
if !ok {
|
||||
return "", envelope.NewError(envelope.InputError, "Provider not found", nil)
|
||||
}
|
||||
return oauthCfg.AuthCodeURL(state), nil
|
||||
}
|
||||
|
||||
// ExchangeOIDCToken takes an OIDC authorization code, validates it, and returns an OIDC token for subsequent auth.
|
||||
func (a *Auth) ExchangeOIDCToken(ctx context.Context, code string) (string, OIDCclaim, error) {
|
||||
tk, err := a.oauthCfg.Exchange(ctx, code)
|
||||
func (a *Auth) ExchangeOIDCToken(ctx context.Context, providerID int, code string) (string, OIDCclaim, error) {
|
||||
oauthCfg, ok := a.oauthCfgs[providerID]
|
||||
if !ok {
|
||||
return "", OIDCclaim{}, fmt.Errorf("invalid provider ID: %d", providerID)
|
||||
}
|
||||
|
||||
verifier, ok := a.verifiers[providerID]
|
||||
if !ok {
|
||||
return "", OIDCclaim{}, fmt.Errorf("invalid provider ID: %d", providerID)
|
||||
}
|
||||
|
||||
tk, err := oauthCfg.Exchange(ctx, code)
|
||||
if err != nil {
|
||||
return "", OIDCclaim{}, fmt.Errorf("error exchanging token: %v", err)
|
||||
}
|
||||
@@ -104,7 +129,7 @@ func (a *Auth) ExchangeOIDCToken(ctx context.Context, code string) (string, OIDC
|
||||
}
|
||||
|
||||
// Parse and verify ID Token payload.
|
||||
idTk, err := a.verifier.Verify(ctx, rawIDTk)
|
||||
idTk, err := verifier.Verify(ctx, rawIDTk)
|
||||
if err != nil {
|
||||
return "", OIDCclaim{}, fmt.Errorf("error verifying ID token: %v", err)
|
||||
}
|
||||
@@ -117,10 +142,10 @@ func (a *Auth) ExchangeOIDCToken(ctx context.Context, code string) (string, OIDC
|
||||
}
|
||||
|
||||
// SaveSession creates and sets a session (post successful login/auth).
|
||||
func (o *Auth) SaveSession(user models.User, r *fastglue.Request) error {
|
||||
sess, err := o.sess.NewSession(r, r)
|
||||
func (a *Auth) SaveSession(user models.User, r *fastglue.Request) error {
|
||||
sess, err := a.sess.NewSession(r, r)
|
||||
if err != nil {
|
||||
o.lo.Error("error creating login session", "error", err)
|
||||
a.logger.Error("error creating login session", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -130,15 +155,15 @@ func (o *Auth) SaveSession(user models.User, r *fastglue.Request) error {
|
||||
"first_name": user.FirstName,
|
||||
"last_name": user.LastName,
|
||||
}); err != nil {
|
||||
o.lo.Error("error setting login session", "error", err)
|
||||
a.logger.Error("error setting login session", "error", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateSession validates session and returns the user.
|
||||
func (o *Auth) ValidateSession(r *fastglue.Request) (models.User, error) {
|
||||
sess, err := o.sess.Acquire(r.RequestCtx, r, r)
|
||||
func (a *Auth) ValidateSession(r *fastglue.Request) (models.User, error) {
|
||||
sess, err := a.sess.Acquire(r.RequestCtx, r, r)
|
||||
if err != nil {
|
||||
return models.User{}, err
|
||||
}
|
||||
@@ -158,7 +183,7 @@ func (o *Auth) ValidateSession(r *fastglue.Request) (models.User, error) {
|
||||
|
||||
// Logged in?
|
||||
if userID <= 0 {
|
||||
o.lo.Error("error fetching session", "error", err)
|
||||
a.logger.Error("error fetching session", "error", err)
|
||||
return models.User{}, err
|
||||
}
|
||||
|
||||
@@ -171,14 +196,14 @@ func (o *Auth) ValidateSession(r *fastglue.Request) (models.User, error) {
|
||||
}
|
||||
|
||||
// DestroySession destroys session
|
||||
func (o *Auth) DestroySession(r *fastglue.Request) error {
|
||||
sess, err := o.sess.Acquire(r.RequestCtx, r, r)
|
||||
func (a *Auth) DestroySession(r *fastglue.Request) error {
|
||||
sess, err := a.sess.Acquire(r.RequestCtx, r, r)
|
||||
if err != nil {
|
||||
o.lo.Error("error acquiring session", "error", err)
|
||||
a.logger.Error("error acquiring session", "error", err)
|
||||
return err
|
||||
}
|
||||
if err := sess.Destroy(); err != nil {
|
||||
o.lo.Error("error clearing session", "error", err)
|
||||
a.logger.Error("error clearing session", "error", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@@ -34,6 +34,8 @@ func (c *Client) Put(filename string, cType string, src io.ReadSeeker) (string,
|
||||
|
||||
// Get the directory path
|
||||
dir := getDir(c.opts.UploadPath)
|
||||
fmt.Println("dir ", dir)
|
||||
fmt.Println("-- ", c.opts.UploadPath)
|
||||
o, err := os.OpenFile(filepath.Join(dir, filename), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -10,35 +9,28 @@ type OIDC struct {
|
||||
ID int `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
Name string `db:"-" json:"name"`
|
||||
ProviderLogoURL string `db:"-" json:"logo_url"`
|
||||
ProviderURL string `db:"provider_url" json:"provider_url"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Disabled bool `db:"disabled" json:"disabled"`
|
||||
ClientID string `db:"client_id" json:"client_id"`
|
||||
ClientSecret string `db:"client_secret" json:"client_secret"`
|
||||
RedirectURI string `db:"redirect_uri" json:"redirect_uri"`
|
||||
Provider string `db:"provider" json:"provider"`
|
||||
ProviderURL string `db:"provider_url" json:"provider_url"`
|
||||
RedirectURI string `db:"-" json:"redirect_uri"`
|
||||
ProviderLogoURL string `db:"-" json:"logo_url"`
|
||||
}
|
||||
|
||||
// ProviderInfo holds the name and logo of a provider.
|
||||
type ProviderInfo struct {
|
||||
Name string
|
||||
Logo string
|
||||
// providerLogos holds known provider logos.
|
||||
var providerLogos = map[string]string{
|
||||
"Google": "/images/google-logo.png",
|
||||
"Github": "/images/github-logo.png",
|
||||
"Custom": "",
|
||||
}
|
||||
|
||||
var providerMap = map[string]ProviderInfo{
|
||||
"accounts.google.com": {Name: "Google", Logo: "https://lh3.googleusercontent.com/COxitqgJr1sJnIDe8-jiKhxDx1FrYbtRHKJ9z_hELisAlapwE9LUPh6fcXIfb5vwpbMl4xl9H9TRFPc5NOO8Sb3VSgIBrfRYvW6cUA"},
|
||||
"microsoftonline.com": {Name: "Microsoft", Logo: "https://logo"},
|
||||
"github.com": {Name: "Github", Logo: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTrg0GanJf8uJHY8yuvL6Vyk47iVTx-AchsAA&s"},
|
||||
}
|
||||
|
||||
// SetProviderInfo adds provider name and logo to an OIDC model.
|
||||
func (oidc *OIDC) SetProviderInfo() {
|
||||
for url, info := range providerMap {
|
||||
if strings.Contains(oidc.ProviderURL, url) {
|
||||
oidc.Name = info.Name
|
||||
oidc.ProviderLogoURL = info.Logo
|
||||
return
|
||||
// SetProviderLogo provider logo to the OIDC model.
|
||||
func (oidc *OIDC) SetProviderLogo() {
|
||||
for provider, logo := range providerLogos {
|
||||
if oidc.Provider == provider {
|
||||
oidc.ProviderLogoURL = logo
|
||||
}
|
||||
}
|
||||
oidc.Name = "Custom"
|
||||
oidc.ProviderLogoURL = "https://path_to_default_logo"
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@ type queries struct {
|
||||
UpdateOIDC *sqlx.Stmt `query:"update-oidc"`
|
||||
DeleteOIDC *sqlx.Stmt `query:"delete-oidc"`
|
||||
}
|
||||
|
||||
// New creates and returns a new instance of the oidc Manager.
|
||||
func New(opts Opts) (*Manager, error) {
|
||||
var q queries
|
||||
@@ -56,7 +57,7 @@ func (o *Manager) Get(id int) (models.OIDC, error) {
|
||||
o.lo.Error("error fetching oidc", "error", err)
|
||||
return oidc, envelope.NewError(envelope.GeneralError, "Error fetching OIDC", nil)
|
||||
}
|
||||
oidc.SetProviderInfo()
|
||||
oidc.SetProviderLogo()
|
||||
return oidc, nil
|
||||
}
|
||||
|
||||
@@ -68,23 +69,23 @@ func (o *Manager) GetAll() ([]models.OIDC, error) {
|
||||
return oidc, envelope.NewError(envelope.GeneralError, "Error fetching OIDC", nil)
|
||||
}
|
||||
for i := range oidc {
|
||||
oidc[i].SetProviderInfo()
|
||||
oidc[i].SetProviderLogo()
|
||||
}
|
||||
return oidc, nil
|
||||
}
|
||||
|
||||
// Create adds a new oidc.
|
||||
func (o *Manager) Create(oidc models.OIDC) error {
|
||||
if _, err := o.q.InsertOIDC.Exec(oidc.ProviderURL, oidc.ClientID, oidc.ClientSecret, oidc.RedirectURI); err != nil {
|
||||
if _, err := o.q.InsertOIDC.Exec(oidc.Name, oidc.Provider, oidc.ProviderURL, oidc.ClientID, oidc.ClientSecret); err != nil {
|
||||
o.lo.Error("error inserting oidc", "error", err)
|
||||
return envelope.NewError(envelope.GeneralError, "Error fetching OIDC", nil)
|
||||
return envelope.NewError(envelope.GeneralError, "Error creating OIDC", nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create updates a oidc by id.
|
||||
func (o *Manager) Update(id int, oidc models.OIDC) error {
|
||||
if _, err := o.q.UpdateOIDC.Exec(id, oidc.ProviderURL, oidc.ClientID, oidc.ClientSecret, oidc.RedirectURI); err != nil {
|
||||
if _, err := o.q.UpdateOIDC.Exec(id, oidc.Name, oidc.Provider, oidc.ProviderURL, oidc.ClientID, oidc.ClientSecret, oidc.Disabled); err != nil {
|
||||
o.lo.Error("error updating oidc", "error", err)
|
||||
return envelope.NewError(envelope.GeneralError, "Error updating OIDC", nil)
|
||||
}
|
||||
|
@@ -1,19 +1,17 @@
|
||||
-- name: get-all-oidc
|
||||
SELECT id, disabled, provider_url, updated_at FROM oidc;
|
||||
SELECT id, name, disabled, provider_url, provider, client_id, client_secret, updated_at FROM oidc order by updated_at desc;
|
||||
|
||||
-- name: get-oidc
|
||||
SELECT * FROM oidc WHERE id = $1;
|
||||
|
||||
-- name: insert-oidc
|
||||
INSERT INTO oidc (provider_url, client_id, client_secret, redirect_uri)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
INSERT INTO oidc (name, provider, provider_url, client_id, client_secret)
|
||||
VALUES ($1, $2, $3, $4, $5);
|
||||
|
||||
-- name: update-oidc
|
||||
UPDATE oidc
|
||||
SET provider_url = $2, client_id = $3, client_secret = $4, redirect_uri = $5, updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
SET name = $2, provider = $3, provider_url = $4, client_id = $5, client_secret = $6, disabled = $7, updated_at = now()
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: delete-oidc
|
||||
DELETE FROM oidc WHERE id = $1;
|
||||
|
Reference in New Issue
Block a user