Skip to content

Commit

Permalink
Modelo 2.0.4 (#1078)
Browse files Browse the repository at this point in the history
* Update devapp1.yml

New release

* Update playwright-dev.yml

New release

* Update package.json

* dev chgs to reflect new structure

* Bump minimatch from 3.0.4 to 3.1.2 in /studio (#1079)

Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Undo Integrate PlayWright (#1080)

* Bump minimatch from 3.0.4 to 3.1.2 in /studio (#1079)

Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* remove the playwright badge

* un integrate playwright

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Issue 1089 Unique email address (#1105)

* make email column unique

* ignore local configurations & secrets

* open stages in new tab (#1106)

* Issue 1097 Open stages in new tab (cont.) (#1108)

* open stages in new tab

* open as new tab from stage management

* Issue 1089 Update existed user email (#1109)

* test update existed email mutation

* raise error when email address is belongs to another user

* fix unsupported operand types for |

* lock sqlalchemy version

* Issue 1093 Stage table actions (#1110)

* quick login for developers on studio

* fix reactivity not working

* update stage inside studio

* update status & visibility mutation

* table visibility & status toggle

* no split layout (#1111)

* scaffold script enhancement (#1112)

Co-authored-by: gloriajw <aagg@comcast.net>

* consistent open stage behavior (#1113)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: gloriajw <aagg@comcast.net>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Hồng Phát <hongphat.js@gmail.com>
  • Loading branch information
4 people committed Aug 7, 2023
1 parent c5fc61e commit 383e117
Show file tree
Hide file tree
Showing 38 changed files with 398 additions and 335 deletions.
4 changes: 2 additions & 2 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: [ AnchorSteam-2.0.3 ]
branches: [ Modelo-2.0.4 ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -32,7 +32,7 @@ jobs:
script: |
cd /home/upstage/upstage/dashboard/
git fetch
git checkout AnchorSteam-2.0.3
git checkout Modelo-2.0.4
git pull
yarn
yarn build:dev
Expand Down
30 changes: 0 additions & 30 deletions .github/workflows/playwright-dev.yml

This file was deleted.

30 changes: 0 additions & 30 deletions .github/workflows/playwright.yml

This file was deleted.

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ docs/_build
.env.local
.env.*.local

# local configuration files
config/*.py
!config/__init__.py
!config/your_hostname.py

# Log files
npm-debug.log*
yarn-debug.log*
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,20 @@ Finally, pass the incoming request to `UpStage Service`
}
```

## Recipes

### Scaffolding demo content & base media

Execute the scaffold script at:

```bash
python3 scripts/devtools/scaffold-base-media.py
```

The script uses the same configuration as the `upstage.service`, so there is no need to do additional setup.

It will use the media inside `dashboard/demo` folder to create base media, the subfolder of the media will decide its type (for example, an image inside `dashboard/demo/avatar` folder will be uploaded as an avatar, while another image inside `dashboard/demo/prop` would be uploaded as a prop). You will be asked for a username to whom these media will belong. A demo stage will be created afterward, in which all these media are assigned as the default.

## Troubleshooting

### Stages offline when entering with firefox
Expand Down
2 changes: 1 addition & 1 deletion config/dev/upstage_email_token.service
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ After=syslog.target
User=upstage
Group=upstage
Type=simple
ExecStart=/bin/python3 /home/upstage/upstage/run_upstage_email.py
ExecStart=/bin/python3 /home/upstage/upstage/scripts/run_upstage_email.py
StandardOutput=append:/var/log/uwsgi/upstage.log

[Install]
Expand Down
2 changes: 1 addition & 1 deletion config/dev/upstage_event_archive.service
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Description=UpStage event archive service
User=upstage
Group=upstage
Type=simple
ExecStart=/usr/bin/python3 /home/upstage/upstage/run_event_archive.py
ExecStart=/usr/bin/python3 /home/upstage/upstage/scripts/run_event_archive.py

[Install]
WantedBy=multi-user.target
1 change: 1 addition & 0 deletions core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from core.project_globals import app
24 changes: 20 additions & 4 deletions core/auth/auth_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,29 @@ def mutate(self, info, username, password):
user = User.query.filter_by(username=username).first()
if not user:
raise Exception("Authenication Failure : User is not registered")
if decrypt(password) != user.password:
if password != decrypt(user.password):
raise Exception("Authenication Failure : Bad Password")

access_token = create_access_token(identity=user.id)
refresh_token = create_refresh_token(identity=user.id)

user_session = UserSession(
user_id=user.id,
access_token=access_token,
refresh_token=refresh_token,
app_version=request.headers.get("X-Upstage-App-Version"),
app_os_type=request.headers.get("X-Upstage-Os-Type"),
app_os_version=request.headers.get("X-Upstage-Os-Version"),
app_device=request.headers.get("X-Upstage-Device-Model"),
)
with ScopedSession() as local_db_session:
local_db_session.add(user_session)
local_db_session.flush()

return AuthMutation(
access_token=create_access_token(username),
refresh_token=create_refresh_token(username),
access_token,
refresh_token,
)
# TODO: Add session handling, etc.


class RefreshMutation(graphene.Mutation):
Expand Down
24 changes: 13 additions & 11 deletions core/project_globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from flask import Flask, redirect, g, got_request_exception, abort, render_template
from flask import Response, jsonify, make_response, request
from flask_caching import Cache as URLCache
from flask.json import JSONEncoder
from flask.json.provider import JSONProvider

# from flask.exthook import ExtDeprecationWarning
from flask_restx import Api
Expand Down Expand Up @@ -173,19 +173,21 @@ def do403(e):
return render_template("global_templates/403.html"), 403


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CustomJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, datetime.datetime) or isinstance(o, datetime.date):
return o.isoformat()
if isinstance(o, ObjectId) or isinstance(o, Decimal):
return str(o)
return JSONEncoder.default(self, o)
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CustomJSONProvider(JSONProvider):
def dumps(self, obj, **kwargs):
if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date):
return obj.isoformat()
if isinstance(obj, ObjectId) or isinstance(obj, Decimal):
return str(obj)
return json.dumps(obj, **kwargs)

def loads(self, s, **kwargs):
return json.loads(s, **kwargs)

# This is only in effect when you call jsonify()
app.json_encoder = CustomJSONEncoder

# This is only in effect when you call jsonify()
app.json_provider_class = CustomJSONProvider
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

print("ENV_TYPE:{},DEBUG={}".format(ENV_TYPE, DEBUG))
Expand Down
1 change: 1 addition & 0 deletions core/requirements.freeze
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pyotp==2.8.0
pytz==2022.7.1
qrcode==7.4.2
requests==2.28.2
sqlalchemy==1.4.49
stripe==5.2.0
werkzeug==2.2.3
wrapt==1.14.1
3 changes: 3 additions & 0 deletions core/requirements.pip
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ pillow
psycopg2_binary
pymongo
pyotp
pytest
pytz
qrcode
requests
snapshottest
sqlalchemy
stripe
werkzeug
wrapt
6 changes: 5 additions & 1 deletion core/studio/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import graphene
from core.asset.models import Stage as StageModel
from core.asset.models import Tag as TagModel
from core.auth.auth_mutation import RefreshMutation
from core.auth.auth_mutation import AuthMutation, RefreshMutation
from core.project_globals import DBSession, app
from config import URL_PREFIX
from flask_graphql import GraphQLView
Expand All @@ -20,6 +20,7 @@
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
from graphql.execution.executors.asyncio import AsyncioExecutor
from core.stage.asset import DeleteMedia
from core.stage.schema import UpdateAttributeStatus, UpdateAttributeVisibility
from core.user.models import ROLES
from core.user.models import User as UserModel
from core.user.models import role_conv
Expand Down Expand Up @@ -103,10 +104,13 @@ class Mutation(graphene.ObjectType):
deleteMedia = DeleteMedia.Field()
uploadFile = UploadFile.Field()
saveMedia = SaveMedia.Field()
authUser = AuthMutation.Field()
refreshUser = RefreshMutation.Field()
confirmPermission = ConfirmPermission.Field()
requestPermission = RequestPermission.Field()
quickAssignMutation = QuickAssignMutation.Field()
updateStatus = UpdateAttributeStatus.Field()
updateVisibility = UpdateAttributeVisibility.Field()


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
57 changes: 35 additions & 22 deletions core/user/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class Arguments:

async def mutate(self, info, inbound):
data = graphql_utils.input_to_dictionary(inbound)
# We have GUEST role because Helen wants to create batch users for demo purposes
# GUEST users don't neccessarily need an email address to keep batch creation simple
if not data["email"] and data["role"] != GUEST:
raise Exception("Email is required!")
if not data["intro"]:
Expand Down Expand Up @@ -160,28 +162,39 @@ async def mutate(self, info, inbound):
raise Exception("Email is required!")

with ScopedSession() as local_db_session:
user = (
local_db_session.query(UserModel)
.filter(UserModel.id == data["id"])
.first()
)
if data["password"]:
data["password"] = encrypt(data["password"])
else:
del data["password"]
for key, value in data.items():
if key == "active":
if value and not user.active and not user.deactivated_on:
await send(
[user.email],
f"Registration approved for user {user.username}",
user_approved(user),
)
if not value and user.active:
user.deactivated_on = datetime.now()

if hasattr(user, key):
setattr(user, key, value)
try:
user = (
local_db_session.query(UserModel)
.filter(UserModel.id == data["id"])
.first()
)
if data["password"]:
data["password"] = encrypt(data["password"])
else:
del data["password"]
for key, value in data.items():
if key == "active":
if value and not user.active and not user.deactivated_on:
await send(
[user.email],
f"Registration approved for user {user.username}",
user_approved(user),
)
if not value and user.active:
user.deactivated_on = datetime.now()

if hasattr(user, key):
setattr(user, key, value)
local_db_session.flush()
except Exception as e:
if "email" in e.args[0]:
raise Exception(
f"This email address already belongs to another user!"
)
app.logger.error(e)
raise Exception(
f"There was an error updating this user information. Please check the logs and try again later.!"
)

user = DBSession.query(UserModel).filter(UserModel.id == data["id"]).first()
return UpdateUser(user=user)
Expand Down
2 changes: 1 addition & 1 deletion core/user/sqlfiles/create.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ CREATE TABLE public.upstage_user (
id BIGSERIAL NOT NULL,
username TEXT unique not null,
password TEXT not null,
email TEXT,
email TEXT unique default null,
bin_name TEXT not null,
role INTEGER not null default 0,
first_name TEXT default null,
Expand Down
Loading

0 comments on commit 383e117

Please sign in to comment.