Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Issue 325 Custom foyer links and text #694

Merged
merged 6 commits into from
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 58 additions & 7 deletions config/schema.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: iso8859-15 -*-
from os import name
from config.project_globals import ScopedSession, app
from config.project_globals import DBSession, ScopedSession, app
from flask_graphql import GraphQLView
from config.settings import NGINX_CONFIG_FILE, VERSION
from graphene import relay
Expand Down Expand Up @@ -28,29 +28,50 @@ def resolve_uploadLimit(self, info):
return limit


def get_config(name):
config = DBSession.query(ConfigModel).filter(
ConfigModel.name == name).first()
if config:
return config.value


class SystemConfig(graphene.ObjectType):
termsOfService = graphene.String()

def resolve_termsOfService(self, info):
with ScopedSession() as local_db_session:
config = local_db_session.query(ConfigModel).filter(
ConfigModel.name == TERMS_OF_SERVICE
).first()
if config:
return config.value
return get_config(TERMS_OF_SERVICE)


class FoyerConfig(graphene.ObjectType):
title = graphene.String()
description = graphene.String()
menu = graphene.String()

def resolve_title(self, info):
return get_config('FOYER_TITLE')

def resolve_description(self, info):
return get_config('FOYER_DESCRIPTION')

def resolve_menu(self, info):
return get_config('FOYER_MENU')


class Query(graphene.ObjectType):
node = relay.Node.Field()
nginx = graphene.Field(NginxConfig)
system = graphene.Field(SystemConfig)
foyer = graphene.Field(FoyerConfig)

def resolve_nginx(self, info):
return NginxConfig()

def resolve_system(self, info):
return SystemConfig()

def resolve_foyer(self, info):
return FoyerConfig()


class UpdateTermsOfService(graphene.Mutation):
"""Mutation to update Terms of Service's URL."""
Expand All @@ -76,8 +97,38 @@ def mutate(self, info, url):
return UpdateTermsOfService(url=url)


class SaveConfig(graphene.Mutation):
"""Mutation to customise foyer."""
success = graphene.Boolean(description="True if the config was saved.")

class Arguments:
name = graphene.String(
required=True, description="The name of the config.")
value = graphene.String(
required=True, description="The value of the config.")

# decorate this with jwt login decorator.
def mutate(self, info, name, value):
with ScopedSession() as local_db_session:
config = local_db_session.query(ConfigModel).filter(
ConfigModel.name == name).first()

if name == TERMS_OF_SERVICE:
# Use UpdateTermsOfService mutation instead.
return SaveConfig(success=False)

if config:
config.value = value
else:
config = ConfigModel(name=name, value=value)
local_db_session.add(config)

return SaveConfig(success=True)


class Mutation(graphene.ObjectType):
updateTermsOfService = UpdateTermsOfService.Field()
saveConfig = SaveConfig.Field()


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
6 changes: 6 additions & 0 deletions config/sqlfiles/create.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ CREATE TABLE "public"."config" (
"created_on" timestamp DEFAULT (now() at time zone 'utc'),
PRIMARY KEY ("id")
);

-- Seed foyer config
INSERT INTO "config" ("name", "value") VALUES ('FOYER_TITLE', 'CYBERFORMANCE PLATFORM');
INSERT INTO "config" ("name", "value") VALUES ('FOYER_DESCRIPTION', 'UpStage is an online venue for live performance: remote performers collaborate in real time using digital media, and online audiences anywhere in the world join events by going to a web page, without having to download and install any additional software. UpStage is available free to anyone who would like to use it.');
INSERT INTO "config" ("name", "value") VALUES ('FOYER_MENU', 'UpStage User Manual (https://docs.upstage.live/)
Customise Foyer (/backstage/admin/foyer-customisation)');
4 changes: 0 additions & 4 deletions studio/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ def mutate(self, info):
local_db_session.flush()
total += media.size

local_db_session.commit()
local_db_session.close()
return CalcSizes(size=total)


Expand Down Expand Up @@ -398,8 +396,6 @@ def mutate(self, info, id, approved):
else:
local_db_session.delete(asset_usage)
local_db_session.flush()
local_db_session.commit()
local_db_session.close()
permissions = DBSession.query(AssetUsageModel).filter(
AssetUsageModel.asset_id == asset_id).all()
return ConfirmPermission(success=True, permissions=permissions)
Expand Down
96 changes: 35 additions & 61 deletions ui/dashboard/src/components/NavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,63 +17,40 @@

<div :class="{ 'navbar-menu': true, 'is-active': expanded }">
<div class="navbar-start">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless"> About </a>
<div class="navbar-dropdown">
<a class="navbar-item" href="#"> FAQs </a>
<a class="navbar-item" href="#"> Contacts </a>
<a class="navbar-item" href="#"> Diversity + Inclusion </a>
</div>
</div>
<div class="vertical-divider" />
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless"> &nbsp; Learn &nbsp; </a>
<div class="navbar-dropdown">
<a class="navbar-item" href="#"> Research </a>
<div
v-if="!navigations"
class="navbar-item"
style="text-transform: none;"
>Cannot display navigation properly, please check your menu syntax in Admin section!</div>
<template v-else>
<template v-for="(menu, i) in navigations" :key="i">
<div v-if="menu.children" class="navbar-item has-dropdown is-hoverable">
<a
v-if="menu.url"
class="navbar-link is-arrowless"
:href="menu.url"
:target="menu.url?.startsWith('http') ? '_blank' : ''"
>{{ menu.title }}</a>
<a v-else class="navbar-link is-arrowless">{{ menu.title }}</a>
<div class="navbar-dropdown">
<a
v-for="(submenu, j) in menu.children"
:key="{ j }"
class="navbar-item"
:href="submenu.url"
:target="submenu.url?.startsWith('http') ? '_blank' : ''"
>{{ submenu.title }}</a>
</div>
</div>
<a
v-else
class="navbar-item"
href="https://github.com/upstage-org/documentation"
target="_blank"
>
Documentation
</a>
</div>
</div>
<div class="vertical-divider" />
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless"> Festivals </a>
<div class="navbar-dropdown">
<a class="navbar-item" href="#"> 10th Birthday </a>
<a class="navbar-item" href="#"> 121212 </a>
</div>
</div>
<div class="vertical-divider" />
<a
class="navbar-item"
href="https://github.com/upstage-org/upstage/"
target="_blank"
>
Develop
</a>
<div class="vertical-divider" />
<a class="navbar-item" to="/#">Donate</a>
<div class="vertical-divider" />
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless"> Stage </a>
<div class="navbar-dropdown">
<Loading v-if="loadingStages" />
<template v-else>
<router-link
v-for="stage in liveStages"
:key="stage.id"
class="navbar-item"
:to="`/${stage.fileLocation}`"
>
{{ stage.name }}
</router-link>
</template>
</div>
</div>
:href="menu.url"
:target="menu.url?.startsWith('http') ? '_blank' : ''"
>{{ menu.title }}</a>
<div v-if="i < navigations.length - 1" class="vertical-divider" />
</template>
</template>
</div>

<div class="navbar-end">
Expand Down Expand Up @@ -103,25 +80,22 @@ import { computed, ref } from "vue";
import { loggedIn, logout } from "@/utils/auth";
import Logo from "./Logo";
import { useStore } from "vuex";
import Loading from "@/components/Loading";

export default {
components: { Logo, Loading },
components: { Logo },
setup() {
const store = useStore();
const expanded = ref(false);
const toggleExpanded = () => (expanded.value = !expanded.value);

const loadingStages = computed(() => store.getters["cache/loadingStages"]);
const liveStages = computed(() => store.getters["cache/liveStages"]);
const navigations = computed(() => store.getters["config/navigations"]);

return {
expanded,
toggleExpanded,
loggedIn,
logout,
loadingStages,
liveStages,
navigations
};
},
};
Expand Down
5 changes: 5 additions & 0 deletions ui/dashboard/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ const routes = [
name: 'System Configurations',
component: () => import('../views/backstage/Admin/SystemConfigurations.vue'),
},
{
path: 'foyer-customisation',
name: 'Foyer Customisation',
component: () => import('../views/backstage/Admin/FoyerCustomisation.vue'),
}
]
},
{
Expand Down
14 changes: 13 additions & 1 deletion ui/dashboard/src/services/graphql/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export default {
system {
termsOfService
}
foyer {
title
description
menu
}
}
`),
updateTermsOfService: (variables) => client.request(gql`
Expand All @@ -20,5 +25,12 @@ export default {
url
}
}
`, variables)
`, variables),
saveConfig: (name, value) => client.request(gql`
mutation SaveConfig($name: String!, $value: String!) {
saveConfig(name: $name, value: $value) {
success
}
}
`, { name, value }),
}
34 changes: 33 additions & 1 deletion ui/dashboard/src/store/modules/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,46 @@ export default {
namespaced: true,
state: {
nginx: {},
system: {}
system: {},
foyer: null
},
getters: {
uploadLimit(state) {
return state.nginx.uploadLimit ?? 1024 * 1024
},
termsOfService(state) {
return state.system.termsOfService
},
foyer(state) {
return state.foyer ?? {}
},
navigations(state) {
if (!state.foyer) {
return []
}
try {
const lines = state.foyer.menu.split("\n").filter(line => line.trim().length > 0)
const navigations = []
for (const line of lines) {
// Syntax: <title> (<url>)
const url = line.match(/\(([^)]+)\)/) // get the url part
let title = line.replace('>', '')
title = title.includes("(") ? title.split("(")[0].trim() : title.trim() // get the title part
const menu = { title, url: url ? url[1] : null }
if (line.trim().startsWith(">")) {
const parent = navigations[navigations.length - 1]
if (!parent.children) {
parent.children = []
}
parent.children.push(menu)
} else {
navigations.push(menu)
}
}
return navigations
} catch (error) {
console.log(error)
}
}
},
mutations: {
Expand Down
1 change: 0 additions & 1 deletion ui/dashboard/src/styles/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ div.moveable-control-box {
margin: 8px 12px;
padding: 0 20px !important;
justify-content: center;
text-transform: uppercase;
border: 1px solid transparent;
}
.vertical-divider {
Expand Down
1 change: 0 additions & 1 deletion ui/dashboard/src/styles/mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
@mixin textShadow() {
color: $black;
text-shadow: -3px 0 $primary;
text-transform: uppercase;
}
@mixin differentiatedToolbar($color) {
background-color: $color;
Expand Down
Loading