Adding query save, fixing routing to handle existing rest queries, adding in full saving of enabled headers functionality, fixing various issues discovered while testing.
This commit is contained in:
parent
b31cd5b6f7
commit
c0512fa242
|
@ -0,0 +1,37 @@
|
||||||
|
<script>
|
||||||
|
import { Label, Select } from "@budibase/bbui"
|
||||||
|
import { permissions, roles } from "stores/backend"
|
||||||
|
|
||||||
|
export let query
|
||||||
|
export let saveId
|
||||||
|
export let label
|
||||||
|
|
||||||
|
$: updateRole(roleId, saveId)
|
||||||
|
|
||||||
|
let roleId
|
||||||
|
|
||||||
|
async function updateRole(role, id) {
|
||||||
|
roleId = role
|
||||||
|
const queryId = query?._id || id
|
||||||
|
if (roleId && queryId) {
|
||||||
|
for (let level of ["read", "write"]) {
|
||||||
|
await permissions.save({
|
||||||
|
level,
|
||||||
|
role,
|
||||||
|
resource: queryId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if label}
|
||||||
|
<Label>{label}</Label>
|
||||||
|
{/if}
|
||||||
|
<Select
|
||||||
|
value={roleId}
|
||||||
|
on:change={e => updateRole(e.detail)}
|
||||||
|
options={$roles}
|
||||||
|
getOptionLabel={x => x.name}
|
||||||
|
getOptionValue={x => x._id}
|
||||||
|
/>
|
|
@ -14,32 +14,60 @@
|
||||||
|
|
||||||
export let defaults
|
export let defaults
|
||||||
export let object = defaults || {}
|
export let object = defaults || {}
|
||||||
|
export let activity = {}
|
||||||
export let readOnly
|
export let readOnly
|
||||||
export let noAddButton
|
export let noAddButton
|
||||||
export let name
|
export let name
|
||||||
export let headings = false
|
export let headings = false
|
||||||
export let activity = false
|
|
||||||
export let options
|
export let options
|
||||||
|
export let toggle
|
||||||
|
|
||||||
let fields = Object.entries(object).map(([name, value]) => ({ name, value }))
|
let fields = Object.entries(object).map(([name, value]) => ({ name, value }))
|
||||||
|
let fieldActivity = []
|
||||||
|
|
||||||
$: object = fields.reduce(
|
$: object = fields.reduce(
|
||||||
(acc, next) => ({ ...acc, [next.name]: next.value }),
|
(acc, next) => ({ ...acc, [next.name]: next.value }),
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
$: fieldActivity = buildFieldActivity(activity)
|
||||||
|
|
||||||
|
function buildFieldActivity(obj) {
|
||||||
|
if (!obj || typeof obj !== "object") {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const array = Array(fields.length)
|
||||||
|
for (let [key, value] of Object.entries(obj)) {
|
||||||
|
const field = fields.find(el => el.name === key)
|
||||||
|
const idx = fields.indexOf(field)
|
||||||
|
if (idx !== -1) {
|
||||||
|
array[idx] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}
|
||||||
|
|
||||||
export function addEntry() {
|
export function addEntry() {
|
||||||
fields = [...fields, { name: "", value: "" }]
|
fields = [...fields, { name: "", value: "" }]
|
||||||
|
fieldActivity = [...fieldActivity, true]
|
||||||
changed()
|
changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteEntry(idx) {
|
function deleteEntry(idx) {
|
||||||
fields.splice(idx, 1)
|
fields.splice(idx, 1)
|
||||||
|
fieldActivity.splice(idx, 1)
|
||||||
changed()
|
changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changed() {
|
function changed() {
|
||||||
fields = fields
|
fields = fields
|
||||||
|
const newActivity = {}
|
||||||
|
for (let idx = 0; idx < fields.length; idx++) {
|
||||||
|
const fieldName = fields[idx].name
|
||||||
|
if (fieldName) {
|
||||||
|
newActivity[fieldName] = fieldActivity[idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activity = newActivity
|
||||||
dispatch("change", fields)
|
dispatch("change", fields)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -67,8 +95,12 @@
|
||||||
on:change={changed}
|
on:change={changed}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if activity}
|
{#if toggle}
|
||||||
<Toggle />
|
<Toggle
|
||||||
|
bind:value={fieldActivity[idx]}
|
||||||
|
on:change={changed}
|
||||||
|
default={true}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
{#if !readOnly}
|
{#if !readOnly}
|
||||||
<Icon hoverable name="Close" on:click={() => deleteEntry(idx)} />
|
<Icon hoverable name="Close" on:click={() => deleteEntry(idx)} />
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
datasources,
|
datasources,
|
||||||
integrations,
|
integrations,
|
||||||
queries,
|
queries,
|
||||||
roles,
|
|
||||||
permissions,
|
permissions,
|
||||||
} from "stores/backend"
|
} from "stores/backend"
|
||||||
import { capitalise } from "../../helpers"
|
import { capitalise } from "../../helpers"
|
||||||
|
@ -32,6 +31,7 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import KeyValueBuilder from "./KeyValueBuilder.svelte"
|
import KeyValueBuilder from "./KeyValueBuilder.svelte"
|
||||||
import { fieldsToSchema, schemaToFields } from "helpers/data/utils"
|
import { fieldsToSchema, schemaToFields } from "helpers/data/utils"
|
||||||
|
import AccessLevelSelect from "./AccessLevelSelect.svelte"
|
||||||
|
|
||||||
export let query
|
export let query
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
let parameters
|
let parameters
|
||||||
let data = []
|
let data = []
|
||||||
let roleId
|
let roleId
|
||||||
|
let saveId
|
||||||
const transformerDocs =
|
const transformerDocs =
|
||||||
"https://docs.budibase.com/building-apps/data/transformers"
|
"https://docs.budibase.com/building-apps/data/transformers"
|
||||||
|
|
||||||
|
@ -62,19 +63,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateRole(role, id = null) {
|
|
||||||
roleId = role
|
|
||||||
if (query?._id || id) {
|
|
||||||
for (let level of ["read", "write"]) {
|
|
||||||
await permissions.save({
|
|
||||||
level,
|
|
||||||
role,
|
|
||||||
resource: query?._id || id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function populateExtraQuery(extraQueryFields) {
|
function populateExtraQuery(extraQueryFields) {
|
||||||
query.fields.extra = extraQueryFields
|
query.fields.extra = extraQueryFields
|
||||||
}
|
}
|
||||||
|
@ -99,7 +87,7 @@
|
||||||
async function saveQuery() {
|
async function saveQuery() {
|
||||||
try {
|
try {
|
||||||
const { _id } = await queries.save(query.datasourceId, query)
|
const { _id } = await queries.save(query.datasourceId, query)
|
||||||
await updateRole(roleId, _id)
|
saveId = _id
|
||||||
notifications.success(`Query saved successfully.`)
|
notifications.success(`Query saved successfully.`)
|
||||||
$goto(`../${_id}`)
|
$goto(`../${_id}`)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -142,14 +130,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="config-field">
|
<div class="config-field">
|
||||||
<Label>Access level</Label>
|
<AccessLevelSelect {saveId} {query} label="Access Level" />
|
||||||
<Select
|
|
||||||
value={roleId}
|
|
||||||
on:change={e => updateRole(e.detail)}
|
|
||||||
options={$roles}
|
|
||||||
getOptionLabel={x => x.name}
|
|
||||||
getOptionValue={x => x._id}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{#if integrationInfo?.extra && query.queryVerb}
|
{#if integrationInfo?.extra && query.queryVerb}
|
||||||
<ExtraQueryConfig
|
<ExtraQueryConfig
|
||||||
|
|
|
@ -17,3 +17,35 @@ export function fieldsToSchema(fields) {
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function breakQueryString(qs) {
|
||||||
|
if (!qs) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
if (qs.includes("?")) {
|
||||||
|
qs = qs.split("?")[1]
|
||||||
|
}
|
||||||
|
const params = qs.split("&")
|
||||||
|
let paramObj = {}
|
||||||
|
for (let param of params) {
|
||||||
|
const [key, value] = param.split("=")
|
||||||
|
paramObj[key] = value
|
||||||
|
}
|
||||||
|
return paramObj
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildQueryString(obj) {
|
||||||
|
let str = ""
|
||||||
|
if (obj) {
|
||||||
|
for (let [key, value] of Object.entries(obj)) {
|
||||||
|
if (!key || key === "") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (str !== "") {
|
||||||
|
str += "&"
|
||||||
|
}
|
||||||
|
str += `${key}=${value || ""}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { store, automationStore } from "builderStore"
|
import { store, automationStore } from "builderStore"
|
||||||
import { roles } from "stores/backend"
|
import { roles, flags } from "stores/backend"
|
||||||
import { Icon, ActionGroup, Tabs, Tab, notifications } from "@budibase/bbui"
|
import { Icon, ActionGroup, Tabs, Tab, notifications } from "@budibase/bbui"
|
||||||
import DeployModal from "components/deploy/DeployModal.svelte"
|
import DeployModal from "components/deploy/DeployModal.svelte"
|
||||||
import RevertModal from "components/deploy/RevertModal.svelte"
|
import RevertModal from "components/deploy/RevertModal.svelte"
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
}
|
}
|
||||||
await automationStore.actions.fetch()
|
await automationStore.actions.fetch()
|
||||||
await roles.fetch()
|
await roles.fetch()
|
||||||
|
await flags.fetch()
|
||||||
return pkg
|
return pkg
|
||||||
} else {
|
} else {
|
||||||
throw new Error(pkg)
|
throw new Error(pkg)
|
||||||
|
|
|
@ -4,17 +4,19 @@
|
||||||
import { IntegrationTypes } from "constants/backend"
|
import { IntegrationTypes } from "constants/backend"
|
||||||
import { goto } from "@roxi/routify"
|
import { goto } from "@roxi/routify"
|
||||||
|
|
||||||
|
let datasourceId
|
||||||
if ($params.query) {
|
if ($params.query) {
|
||||||
const query = $queries.list.find(q => q._id === $params.query)
|
const query = $queries.list.find(q => q._id === $params.query)
|
||||||
if (query) {
|
if (query) {
|
||||||
queries.select(query)
|
queries.select(query)
|
||||||
|
datasourceId = query.datasourceId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const datasource = $datasources.list.find(
|
const datasource = $datasources.list.find(
|
||||||
ds => ds._id === $datasources.selected
|
ds => ds._id === $datasources.selected || ds._id === datasourceId
|
||||||
)
|
)
|
||||||
if (datasource?.source === IntegrationTypes.REST) {
|
if (datasource?.source === IntegrationTypes.REST) {
|
||||||
$goto("../rest")
|
$goto(`../rest/${$params.query}`)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<script>
|
||||||
|
import { params } from "@roxi/routify"
|
||||||
|
import { queries } from "stores/backend"
|
||||||
|
|
||||||
|
if ($params.query) {
|
||||||
|
const query = $queries.list.find(q => q._id === $params.query)
|
||||||
|
if (query) {
|
||||||
|
queries.select(query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot />
|
|
@ -1,6 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import { params } from "@roxi/routify"
|
import { params } from "@roxi/routify"
|
||||||
import { datasources, integrations, queries } from "stores/backend"
|
import { datasources, integrations, queries, flags } from "stores/backend"
|
||||||
import {
|
import {
|
||||||
Layout,
|
Layout,
|
||||||
Input,
|
Input,
|
||||||
|
@ -22,10 +22,15 @@
|
||||||
import CodeMirrorEditor, {
|
import CodeMirrorEditor, {
|
||||||
EditorModes,
|
EditorModes,
|
||||||
} from "components/common/CodeMirrorEditor.svelte"
|
} from "components/common/CodeMirrorEditor.svelte"
|
||||||
import RestBodyInput from "../_components/RestBodyInput.svelte"
|
import RestBodyInput from "../../_components/RestBodyInput.svelte"
|
||||||
import { capitalise } from "helpers"
|
import { capitalise } from "helpers"
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import { fieldsToSchema, schemaToFields } from "helpers/data/utils"
|
import {
|
||||||
|
fieldsToSchema,
|
||||||
|
schemaToFields,
|
||||||
|
breakQueryString,
|
||||||
|
buildQueryString,
|
||||||
|
} from "helpers/data/utils"
|
||||||
import {
|
import {
|
||||||
RestBodyTypes as bodyTypes,
|
RestBodyTypes as bodyTypes,
|
||||||
SchemaTypeOptions,
|
SchemaTypeOptions,
|
||||||
|
@ -35,7 +40,8 @@
|
||||||
let query, datasource
|
let query, datasource
|
||||||
let breakQs = {}
|
let breakQs = {}
|
||||||
let url = ""
|
let url = ""
|
||||||
let response, schema
|
let saveId
|
||||||
|
let response, schema, isGet
|
||||||
let datasourceType, integrationInfo, queryConfig, responseSuccess
|
let datasourceType, integrationInfo, queryConfig, responseSuccess
|
||||||
|
|
||||||
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
$: datasource = $datasources.list.find(ds => ds._id === query?.datasourceId)
|
||||||
|
@ -44,6 +50,7 @@
|
||||||
$: queryConfig = integrationInfo?.query
|
$: queryConfig = integrationInfo?.query
|
||||||
$: url = buildUrl(url, breakQs)
|
$: url = buildUrl(url, breakQs)
|
||||||
$: checkQueryName(url)
|
$: checkQueryName(url)
|
||||||
|
$: isGet = query?.queryVerb === "read"
|
||||||
$: responseSuccess =
|
$: responseSuccess =
|
||||||
response?.info?.code >= 200 && response?.info?.code <= 206
|
response?.info?.code >= 200 && response?.info?.code <= 206
|
||||||
|
|
||||||
|
@ -58,35 +65,6 @@
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function breakQueryString(qs) {
|
|
||||||
if (!qs) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
if (qs.includes("?")) {
|
|
||||||
qs = qs.split("?")[1]
|
|
||||||
}
|
|
||||||
const params = qs.split("&")
|
|
||||||
let paramObj = {}
|
|
||||||
for (let param of params) {
|
|
||||||
const [key, value] = param.split("=")
|
|
||||||
paramObj[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildQueryString(obj) {
|
|
||||||
let str = ""
|
|
||||||
for (let [key, value] of Object.entries(obj)) {
|
|
||||||
if (!key || key === "") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (str !== "") {
|
|
||||||
str += "&"
|
|
||||||
}
|
|
||||||
str += `${key}=${value || ""}`
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkQueryName(inputUrl = null) {
|
function checkQueryName(inputUrl = null) {
|
||||||
if (query && (!query.name || query.flags.urlName)) {
|
if (query && (!query.name || query.flags.urlName)) {
|
||||||
query.flags.urlName = true
|
query.flags.urlName = true
|
||||||
|
@ -113,11 +91,19 @@
|
||||||
const queryString = buildQueryString(breakQs)
|
const queryString = buildQueryString(breakQs)
|
||||||
newQuery.fields.path = url.split("?")[0]
|
newQuery.fields.path = url.split("?")[0]
|
||||||
newQuery.fields.queryString = queryString
|
newQuery.fields.queryString = queryString
|
||||||
|
newQuery.schema = fieldsToSchema(schema)
|
||||||
return newQuery
|
return newQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveQuery() {
|
async function saveQuery() {
|
||||||
query.schema = fieldsToSchema(schema)
|
const toSave = buildQuery()
|
||||||
|
try {
|
||||||
|
const { _id } = await queries.save(toSave.datasourceId, toSave)
|
||||||
|
saveId = _id
|
||||||
|
notifications.success(`Request saved successfully.`)
|
||||||
|
} catch (err) {
|
||||||
|
notifications.error(`Error creating query. ${err.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runQuery() {
|
async function runQuery() {
|
||||||
|
@ -138,7 +124,7 @@
|
||||||
query = getSelectedQuery()
|
query = getSelectedQuery()
|
||||||
const qs = query?.fields.queryString
|
const qs = query?.fields.queryString
|
||||||
breakQs = breakQueryString(qs)
|
breakQs = breakQueryString(qs)
|
||||||
url = buildUrl(query.fields.path, qs)
|
url = buildUrl(query.fields.path, breakQs)
|
||||||
schema = schemaToFields(query.schema)
|
schema = schemaToFields(query.schema)
|
||||||
if (query && !query.transformer) {
|
if (query && !query.transformer) {
|
||||||
query.transformer = "return data"
|
query.transformer = "return data"
|
||||||
|
@ -146,7 +132,6 @@
|
||||||
if (query && !query.flags) {
|
if (query && !query.flags) {
|
||||||
query.flags = {
|
query.flags = {
|
||||||
urlName: false,
|
urlName: false,
|
||||||
bannerCleared: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (query && !query.fields.bodyType) {
|
if (query && !query.fields.bodyType) {
|
||||||
|
@ -187,15 +172,16 @@
|
||||||
<Tab title="Headers">
|
<Tab title="Headers">
|
||||||
<KeyValueBuilder
|
<KeyValueBuilder
|
||||||
bind:object={query.fields.headers}
|
bind:object={query.fields.headers}
|
||||||
|
bind:activity={query.fields.enabledHeaders}
|
||||||
|
toggle
|
||||||
name="header"
|
name="header"
|
||||||
headings
|
headings
|
||||||
activity
|
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Body">
|
<Tab title="Body">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
bind:value={query.fields.bodyType}
|
bind:value={query.fields.bodyType}
|
||||||
options={bodyTypes}
|
options={isGet ? [bodyTypes[0]] : bodyTypes}
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
getOptionLabel={option => option.name}
|
getOptionLabel={option => option.name}
|
||||||
getOptionValue={option => option.value}
|
getOptionValue={option => option.value}
|
||||||
|
@ -204,11 +190,12 @@
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Transformer">
|
<Tab title="Transformer">
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
{#if !query.flags.bannerCleared}
|
{#if !$flags.queryTransformerBanner}
|
||||||
<Banner
|
<Banner
|
||||||
extraButtonText="Learn more"
|
extraButtonText="Learn more"
|
||||||
extraButtonAction={learnMoreBanner}
|
extraButtonAction={learnMoreBanner}
|
||||||
on:change={() => (query.flags.bannerCleared = true)}
|
on:change={() =>
|
||||||
|
flags.updateFlag("queryTransformerBanner", true)}
|
||||||
>
|
>
|
||||||
Add a JavaScript function to transform the query result.
|
Add a JavaScript function to transform the query result.
|
||||||
</Banner>
|
</Banner>
|
|
@ -1,4 +0,0 @@
|
||||||
<script>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<slot />
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { writable } from "svelte/store"
|
||||||
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
export function createFlagsStore() {
|
||||||
|
const { subscribe, set } = writable({})
|
||||||
|
|
||||||
|
return {
|
||||||
|
subscribe,
|
||||||
|
fetch: async () => {
|
||||||
|
const { doc, response } = await getFlags()
|
||||||
|
set(doc)
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
updateFlag: async (flag, value) => {
|
||||||
|
const response = await api.post("/api/users/flags", {
|
||||||
|
flag,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
if (response.status === 200) {
|
||||||
|
const { doc } = await getFlags()
|
||||||
|
set(doc)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFlags() {
|
||||||
|
const response = await api.get("/api/users/flags")
|
||||||
|
let doc = {}
|
||||||
|
if (response.status === 200) {
|
||||||
|
doc = await response.json()
|
||||||
|
}
|
||||||
|
return { doc, response }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const flags = createFlagsStore()
|
|
@ -7,3 +7,4 @@ export { roles } from "./roles"
|
||||||
export { datasources } from "./datasources"
|
export { datasources } from "./datasources"
|
||||||
export { integrations } from "./integrations"
|
export { integrations } from "./integrations"
|
||||||
export { queries } from "./queries"
|
export { queries } from "./queries"
|
||||||
|
export { flags } from "./flags"
|
||||||
|
|
|
@ -2,6 +2,7 @@ const CouchDB = require("../../db")
|
||||||
const {
|
const {
|
||||||
generateUserMetadataID,
|
generateUserMetadataID,
|
||||||
getUserMetadataParams,
|
getUserMetadataParams,
|
||||||
|
generateUserFlagID,
|
||||||
} = require("../../db/utils")
|
} = require("../../db/utils")
|
||||||
const { InternalTables } = require("../../db/utils")
|
const { InternalTables } = require("../../db/utils")
|
||||||
const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
|
const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
|
||||||
|
@ -195,3 +196,35 @@ exports.destroyMetadata = async function (ctx) {
|
||||||
exports.findMetadata = async function (ctx) {
|
exports.findMetadata = async function (ctx) {
|
||||||
ctx.body = await getFullUser(ctx, ctx.params.id)
|
ctx.body = await getFullUser(ctx, ctx.params.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.setFlag = async function (ctx) {
|
||||||
|
const userId = ctx.user._id
|
||||||
|
const { flag, value } = ctx.request.body
|
||||||
|
if (!flag) {
|
||||||
|
ctx.throw(400, "Must supply a 'flag' field in request body.")
|
||||||
|
}
|
||||||
|
const flagDocId = generateUserFlagID(userId)
|
||||||
|
const db = new CouchDB(ctx.appId)
|
||||||
|
let doc
|
||||||
|
try {
|
||||||
|
doc = await db.get(flagDocId)
|
||||||
|
} catch (err) {
|
||||||
|
doc = { _id: flagDocId }
|
||||||
|
}
|
||||||
|
doc[flag] = value || true
|
||||||
|
await db.put(doc)
|
||||||
|
ctx.body = { message: "Flag set successfully" }
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getFlags = async function (ctx) {
|
||||||
|
const userId = ctx.user._id
|
||||||
|
const docId = generateUserFlagID(userId)
|
||||||
|
const db = new CouchDB(ctx.appId)
|
||||||
|
let doc
|
||||||
|
try {
|
||||||
|
doc = await db.get(docId)
|
||||||
|
} catch (err) {
|
||||||
|
doc = { _id: docId }
|
||||||
|
}
|
||||||
|
ctx.body = doc
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ function generateQueryValidation() {
|
||||||
extra: Joi.object().optional(),
|
extra: Joi.object().optional(),
|
||||||
schema: Joi.object({}).required().unknown(true),
|
schema: Joi.object({}).required().unknown(true),
|
||||||
transformer: Joi.string().optional(),
|
transformer: Joi.string().optional(),
|
||||||
|
flags: Joi.object().optional(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,5 +39,15 @@ router
|
||||||
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
||||||
controller.syncUser
|
controller.syncUser
|
||||||
)
|
)
|
||||||
|
.post(
|
||||||
|
"/api/users/flags",
|
||||||
|
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
||||||
|
controller.setFlag
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/api/users/flags",
|
||||||
|
authorized(PermissionTypes.USER, PermissionLevels.READ),
|
||||||
|
controller.getFlags
|
||||||
|
)
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
|
|
@ -40,6 +40,7 @@ const DocumentTypes = {
|
||||||
DEPLOYMENTS: "deployments",
|
DEPLOYMENTS: "deployments",
|
||||||
METADATA: "metadata",
|
METADATA: "metadata",
|
||||||
MEM_VIEW: "view",
|
MEM_VIEW: "view",
|
||||||
|
USER_FLAG: "flag",
|
||||||
}
|
}
|
||||||
|
|
||||||
const ViewNames = {
|
const ViewNames = {
|
||||||
|
@ -339,6 +340,14 @@ exports.getQueryParams = (datasourceId = null, otherProps = {}) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new flag document ID.
|
||||||
|
* @returns {string} The ID of the flag document that was generated.
|
||||||
|
*/
|
||||||
|
exports.generateUserFlagID = userId => {
|
||||||
|
return `${DocumentTypes.USER_FLAG}${SEPARATOR}${userId}`
|
||||||
|
}
|
||||||
|
|
||||||
exports.generateMetadataID = (type, entityId) => {
|
exports.generateMetadataID = (type, entityId) => {
|
||||||
return `${DocumentTypes.METADATA}${SEPARATOR}${type}${SEPARATOR}${entityId}`
|
return `${DocumentTypes.METADATA}${SEPARATOR}${type}${SEPARATOR}${entityId}`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue