Skip to content

Commit

Permalink
TC-14 (#685)
Browse files Browse the repository at this point in the history
* Update devapp1.yml

* preload backdrop and prop frames (#690)

* Upstage Studio V1.3 (#692)

* media permission table

* media copyright level and user list

* media permission tab

* notification system

* request permission and send acknowledgment

* fix relationships warning

* fix relationships warning (cont)

* fix db_id warnings

* show permission tab on create media

* fix square frame and delete asset usages

* configuration changes

* separated config based on enviroments and ignore local .env

* github workflows for meta app

* new static path in nginx

* new upstage path in navigations and refs

* Issue 325 Custom foyer links and text (#694)

* title and description mutation

* navigation customisations

* text area description

* no text-transform and support html

* relative customise foyer link

* remove unnecessary commit and close

Co-authored-by: Hồng Phát <hongphat.js@gmail.com>
Co-authored-by: gloriajw <gloriajw@users.noreply.github.com>
  • Loading branch information
3 people committed Dec 19, 2023
1 parent 1d1c649 commit 1717e05
Show file tree
Hide file tree
Showing 61 changed files with 1,253 additions and 294 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/app1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ jobs:
yarn build
systemctl restart upstage.service
systemctl restart event_archive.service
chown -R upstage:upstage /home/upstage/upstage
chown -R upstage:upstage /home/upstage/upstage
10 changes: 5 additions & 5 deletions .github/workflows/devapp1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: DEVAPP1 CI
on:
# Triggers the workflow on push or approved pull request on R1-2021 branch
push:
branches: [ MB-13 ]
branches: [ TC-14 ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -30,15 +30,15 @@ jobs:
key: ${{ secrets.DEVAPP1_KEY }}
port: ${{ secrets.DEVAPP1_PORT }}
script: |
cd /home/upstage/mobilise/ui/dashboard/
cd /home/upstage/upstage/ui/dashboard/
git fetch
git checkout MB-13
git checkout TC-14
git pull
yarn
yarn build:dev
cd /home/upstage/mobilise/ui/studio/
cd /home/upstage/upstage/ui/studio/
yarn
yarn build:dev
systemctl restart upstage.service
systemctl restart event_archive.service
chown -R upstage:upstage /home/upstage/mobilise
chown -R upstage:upstage /home/upstage/upstage
44 changes: 44 additions & 0 deletions .github/workflows/meta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the action will run.
on:
# Triggers the workflow on push or approved pull request on R1-2021 branch
push:
branches: [ main ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: SSH Remote Commands
# You may pin to the exact commit or the version.
# uses: appleboy/ssh-action@1d1b21ca96111b1eb4c03c21c14ebb971d2200f6
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.META_HOST }}
username: ${{ secrets.META_USERNAME }}
key: ${{ secrets.META_KEY }}
port: ${{ secrets.META_PORT }}
script: |
cd /home/upstage/upstage/ui/dashboard/
git fetch
git checkout main
git pull
yarn
yarn build
cd /home/upstage/upstage/ui/studio/
yarn
yarn build
systemctl restart upstage.service
systemctl restart event_archive.service
chown -R upstage:upstage /home/upstage/upstage
14 changes: 8 additions & 6 deletions asset/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ class Asset(Base, db.Model):
created_on = Column(DateTime, nullable=False, default=datetime.utcnow)
updated_on = Column(DateTime, nullable=False, default=datetime.utcnow)
size = Column(BigInteger, nullable=False, default=0)
copyright_level = Column(Integer, nullable=False, default=0)
asset_type = relationship(AssetType, foreign_keys=[asset_type_id])
asset_license = relationship(AssetLicense, uselist=False, backref="asset")
owner = relationship(User, foreign_keys=[owner_id])
stages = relationship('ParentStage', lazy='dynamic')
tags = relationship('MediaTag', lazy='dynamic')
stages = relationship('ParentStage', lazy='dynamic', back_populates='child_asset')
tags = relationship('MediaTag', lazy='dynamic', back_populates='asset')
permissions = relationship('AssetUsage', lazy='dynamic', back_populates='asset')


class Stage(Base, db.Model):
Expand All @@ -61,8 +63,8 @@ class Stage(Base, db.Model):
file_location = Column(Text, nullable=False)
created_on = Column(DateTime, nullable=False, default=datetime.utcnow)
owner = relationship(User, foreign_keys=[owner_id])
attributes = relationship(lambda: StageAttribute, lazy='dynamic')
assets = relationship('ParentStage', lazy='dynamic')
attributes = relationship(lambda: StageAttribute, lazy='dynamic', back_populates='stage')
assets = relationship('ParentStage', lazy='dynamic', back_populates='stage')


class AssetAttribute(Base, db.Model):
Expand All @@ -88,7 +90,7 @@ class StageAttribute(Base, db.Model):
name = Column(String, nullable=False)
description = Column(Text, nullable=False)
created_on = Column(DateTime, nullable=False, default=datetime.utcnow)
stage = relationship(Stage, foreign_keys=[stage_id])
stage = relationship(Stage, foreign_keys=[stage_id], back_populates="attributes")


class Tag(Base, db.Model):
Expand All @@ -104,5 +106,5 @@ class MediaTag(Base, db.Model):
id = Column(BigInteger, primary_key=True)
asset_id = Column(Integer, ForeignKey(Asset.id), nullable=False, default=0)
tag_id = Column(Integer, ForeignKey(Tag.id), nullable=False, default=0)
asset = relationship(Asset, foreign_keys=[asset_id])
asset = relationship(Asset, foreign_keys=[asset_id], back_populates="tags")
tag = relationship(Tag, foreign_keys=[tag_id])
1 change: 1 addition & 0 deletions asset/sqlfiles/create.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ CREATE TABLE "public"."asset" (
"owner_id" integer NOT NULL,
"description" TEXT default NULL,
"file_location" TEXT NOT NULL,
"copyright_level" integer NOT NULL default 0,
"created_on" timestamp DEFAULT (now() at time zone 'utc'),
"updated_on" timestamp DEFAULT (now() at time zone 'utc'),
"size" BIGINT NOT NULL DEFAULT 0,
Expand Down
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)');
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"description": "UpStage is a platform for cyberformance: remote players combine digital media in real-time for an online audience. All you need is a web browser!",
"logo": "logo.svg",
"github_user": "upstage-org",
"github_repo": "mobilise",
"github_repo": "upstage",
"github_banner": "true",
"page_width": "90%",
"donate_url": "https://upstage.org.nz/?page_id=278",
Expand Down
12 changes: 12 additions & 0 deletions licenses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ class AssetLicense(Base,db.Model):
created_on = Column(DateTime, nullable=False, default=datetime.utcnow)
level = Column(Integer, nullable=False, default=0)
permissions = Column(String, nullable=True)

class AssetUsage(Base,db.Model):
__tablename__ = "asset_usage"
id = Column(BigInteger, primary_key=True)
asset_id = Column(Integer, ForeignKey('asset.id'), nullable=False, default=0)
user_id = Column(Integer, ForeignKey('upstage_user.id'), nullable=False, default=0)
approved = Column(Boolean, nullable=False, default=False)
seen = Column(Boolean, nullable=False, default=False)
note = Column(String, nullable=True)
created_on = Column(DateTime, nullable=False, default=datetime.utcnow)
user = relationship('User', foreign_keys=[user_id])
asset = relationship('Asset', foreign_keys=[asset_id])
18 changes: 16 additions & 2 deletions licenses/sqlfiles/create.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ DROP TABLE IF EXISTS "stage_license";
CREATE TABLE "public"."stage_license" (
"id" BIGSERIAL NOT NULL,
"stage_id" integer NOT NULL,
"created_on" timestamp DEFAULT (now() at time zone 'utc'),
"expires_on" timestamp DEFAULT timezone('utc')) NOT NULL,
"created_on" timestamp without time zone DEFAULT (now() at time zone 'utc'),
"expires_on" timestamp without time zone NOT NULL,
"access_path" character varying unique NOT NULL,
PRIMARY KEY ("id"),
FOREIGN KEY (stage_id) REFERENCES stage(id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE
Expand All @@ -25,3 +25,17 @@ CREATE TABLE "public"."asset_license" (
);

CREATE INDEX "asset_license_created_on" ON "public"."asset_license" USING btree ("created_on");
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DROP TABLE IF EXISTS "asset_usage";
CREATE TABLE "public"."asset_usage" (
"id" BIGSERIAL NOT NULL,
"asset_id" integer NOT NULL,
"user_id" integer NOT NULL,
"approved" boolean NOT NULL DEFAULT false,
"seen" boolean NOT NULL DEFAULT false,
"note" TEXT,
"created_on" timestamp DEFAULT (now() at time zone 'utc'),
PRIMARY KEY ("id"),
FOREIGN KEY (asset_id) REFERENCES asset(id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE,
FOREIGN KEY (user_id) REFERENCES upstage_user(id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE
);
4 changes: 2 additions & 2 deletions performance_config/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ class ParentStage(Base,db.Model):
id = Column(BigInteger, primary_key=True)
stage_id = Column(Integer, ForeignKey(Stage.id), nullable=False, default=0)
child_asset_id = Column(Integer, ForeignKey(Asset.id), nullable=False, default=0)
stage = relationship(Stage, foreign_keys=[stage_id])
child_asset = relationship(Asset, foreign_keys=[child_asset_id])
stage = relationship(Stage, foreign_keys=[stage_id], back_populates="assets")
child_asset = relationship(Asset, foreign_keys=[child_asset_id], back_populates="stages")

class ParentAsset(Base,db.Model):
'''
Expand Down
2 changes: 2 additions & 0 deletions requirements.pip
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ flask-restx
flask-sqlalchemy
flask-talisman
gevent
graphql-core==2.2.1
graphene==2.1.8
graphene-sqlalchemy
paho-mqtt
pillow
Expand Down
4 changes: 3 additions & 1 deletion stage/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from flask_jwt_extended.view_decorators import verify_jwt_in_request
from graphene_sqlalchemy.fields import SQLAlchemyConnectionField
from sqlalchemy.sql.expression import and_, or_
from licenses.models import AssetLicense
from licenses.models import AssetLicense, AssetUsage
import os
from user.models import ADMIN, SUPER_ADMIN
from user.user_utils import current_user
Expand Down Expand Up @@ -362,6 +362,8 @@ def mutate(self, info, id):
MediaTag.asset_id == id).delete(synchronize_session=False)
local_db_session.query(AssetLicense).filter(
AssetLicense.asset_id == id).delete(synchronize_session=False)
local_db_session.query(AssetUsage).filter(
AssetUsage.asset_id == id).delete(synchronize_session=False)

for multiframe_media in local_db_session.query(AssetModel).filter(AssetModel.description.like(f"%{asset.file_location}%")).all():
attributes = json.loads(multiframe_media.description)
Expand Down
4 changes: 3 additions & 1 deletion stage/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ class Stage(SQLAlchemyObjectType):

class Meta:
model = StageModel
model.db_id = model.id
interfaces = (relay.Node,)
connection_class = graphql_utils.CountableConnection

def resolve_db_id(self, info):
return self.id

def resolve_events(self, info, performance_id=None, cursor=0):
events = DBSession.query(EventModel)\
.filter(EventModel.performance_id == performance_id)\
Expand Down
Loading

0 comments on commit 1717e05

Please sign in to comment.