fitzroyacademy / web-app

The main web app
0 stars 0 forks source link

Fitzroy Academy CircleCI

The new LMS for Fitzroy Academy!

Bugs and issues go here: https://github.com/fitzroyacademy/web-app/issues

When setting up the site on a new mac:

First up, clone the repo into a directory somewhere, e.g. ~/dev/web-app

Then, install a bunch of basic stuff:

xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

brew install node
brew upgrade openssl
brew install postgresql
npm install sass -g

export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/

python3 -m venv env

Add this to ~/.bash_profile

# this stuff is for the Fitzroy python app
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/
export FLASK_ENV=development
source ~/dev/web-app/env/bin/activate

Local Installation

This application requires Python 3 to work as well as the libraries listed in requirements.txt.

Manual Installation

Assuming a Python 3 installation, typing this should work.

pip3 install -r ./requirements.txt 
export FLASK_ENV=development
python3 app.py

Restarting the app, assuming everything is installed:

source ./env/bin/activate
python3 app.py

To reseed the DB - this takes everything from stubs.py and puts it in the database dev_db.sqlite, which is our local databse:

Here's the reseed code on all one line for copy/pasting:

rm dev_db.sqlite; flask utils reseed-database; python3 app.py

To make the SCSS work:

sass --watch static/assets/scss/fit.scss static/css/fit.css

To make the subdomains work:

In your /etc/hosts file add the following lines:

127.0.0.1 fitz-dev.com
127.0.0.1 jeditemple.fitz-dev.com
127.0.0.1 some_fancy_subdomain.fitz-dev.com
...

Having such entries in hosts file, the following urls are valid:

fitz-dev.com
jeditemple.fitz-dev.com
some_fancy_subdomain.fitz-dev.com

Note that for local development two domains are obligatory in hosts file, namely fitz-dev.com and jeditemple.fitz-dev.com

To add issues to Github:

https://github.com/fitzroyacademy/web-app/issues

Docker Installation

There's also a Dockerfile for your convenience which can be used instead. All of the application code, including Sass, will be live-reloaded if you edit any files locally with the Docker container running.

From the root repository directory, type:

docker build -t fitzroy-academy .
docker run -p 5000:5000 -e FLASK_ENV=development fitzroy-academy

Server will then be available here: localhost:5000 Example lesson will be available here: localhost:5000/course_intro/01

Docker-compose

There is also a docker-compose.yml file which launches an instance of the app and a Postgres database.

Building and running docker-compose

When you change requirements.txt, you will need to rebuild the containers before running like so:

docker-compose build
docker-compose up # add -d to detach

Stopping docker-compose

docker-compose down

Seeding the DB while using docker-compose

While docker-compose is running:

docker exec -it $(docker ps -f name="fitzroy-academy-app" -q) flask utils reseed-database

Connecting to the docker-compose DB locally

You can open a psql shell like the following:

docker exec -it $$(docker ps -f name="postgres" -q) psql -U postgres

If docker-compose is running, it will also be available via localhost on port 5001.

Reseeding the DB in docker-compose

The previous method will work for both Docker and non-Docker local development with sqlite. If you're using docker-compose, you will need to run the script on the application container:

docker exec -it $(docker ps -f name="fitzroy-academy" -q) flask utils reseed-database

Cleaning out the docker-compose Postgres db (to start fresh):

  1. Ensure the containers aren't running (docker-compose down and docker ps)
  2. Run docker volume list, and find the postgres-container volume (should be like web_app_dbdata)
  3. Run docker volume rm [volume name]

Database migrations

We use Flask-Migrate (Alembic) for database migrations. There are instructions on their page on how to use it properly, but here are the important ones when making DB changes:

flask db migrate [--message MESSAGE] [--sql] [--head HEAD] [--splice] [--branch-label BRANCH_LABEL] [--version-path VERSION_PATH] [--rev-id REV_ID]

Equivalent to revision --autogenerate. The migration script is populated with changes detected automatically. The generated script should to be reviewed and edited as not all types of changes can be detected automatically. This command does not make any changes to the database, just creates the revision script.

Check in your changes and migrations as usual in a PR.

Upgrading packages

# install latest versions of requirements
pip install -r requirements-minimal.txt

# update the pinned dependencies
pip freeze > requirements.txt

Testing, debugging and profiling

You can run tests with make check before you might want to run make format which will run black formatting.

For profiling just run python3.7 profiler and you will get 30 most time consuming methods for each request.

Structure and taxonomy:

Here's the nomenclature and structure for lessons, in hopefully plain English, from top to bottom:

Institute

E.g. "Monash University", or "SHE Investments"

Program

E.g. "Global Challenges" or "Leave No-one Behind"

Course

E.g. "Accelerator", or "Global Challenges"

Access codes

These can be set by the admin, and control access via a short code.

Conditional logic for codes:

This means we have these options in course edit page:

Domain acccess:

Later on: Whitelist

This will require some sort of fancy "invite all these email addresses" thing? Do it later.

Codes are central to user login: They are UIDs for courses. If a teacher wishes to constrain access to a course, they can add a code AND demand that only logged in users can access.

Lesson

Lessons resources:

Resources are links, text and other stuff the student uses while completing lessons. They're at the lesson level within courses.

Resource Translations

A secondary table for translations of default resources is available to provide localized override of all applicable resource data fields.

Resources structure:

Links are added by pasting a url in the lesson editor, the app scrapes the title, figures out the type, and guesses the language. The user can then modify from there.

The featured flag means that link will show up in the right hand nav for easy access, while any non-featured links and the HTML appear in the main resources pane.

Uploads?

No controls for uploading file at the moment. We'll let teachers manage that via dropbox, their own hosting, etc. Just links! :)

Segment

Segments are the chunks of video or text, which students watch / complete within lessons. Each has:

Segment Translations

A secondary table for translations of default segments is available to provide localized override of all applicable segment data fields.

Segment source

Segments can be one of the following types:

Segment types

Segments are of different types to indicate to the user their utility, i.e. a "practical video" is a screengrab of someone using a spreadsheet, wheras a "bonus" video is a nice extra and not needed to complete the course.

Functionality for segment types: Type is mostly used just to set the correct icon type, however some functionality will be attached to type.

Segment statuses

These are changed through student interaction, and indicate progress:

The untouched and touched states are not shown to the student, but are used by teachers and admins.

Completeness is set by a % watched on a segment by segment basis.

Segment languages

Video

Lesson creators will have to upload separate videos if they want differently-languaged audio. Each video within a segment may have one or more subtitle languages.

Subtitles

For YouTube, the subtitle language can be set in the embed, which should integrate with our preferred subtitle language preference; for Wistia, it's based upon the user's browser, with a fallback to the first availabile language for the video.

HTML/Survey

The text and their translations will be stored in the database.

Surveys

The options for surveys / questionnaires are:

Each questionnaire part is either "mandatory" or "optional".


Course permissions

Managed through escalating "security" levels:

And in the future, we will implement:

This is expressed in the course edit with:


Users and permissions

Users

Everything but UID is optional (woah! really? I think so! Wow.)

Registered users

Extra log in options

We're going to encourage users to log in via Google / FB, and this will attach to whatever email we can snag from that login.

This creates a weird flow: If a user does a Google auth, then later tries to sign in via that email without Google, they'll have to a) sign in via Google, or b) do a password reset, as they don't have a password yet.

NB: We need to figure out some clever way of allowing users to auth without email, especially in SEA on phones. Eek.

Anon use case:

For kids (i.e. <16), less technical users, and public courses, it's likely users will never make an account with an email. At this point, we need a very simple way to auth them. Could we rember their device fingerprint perhaps? Or let them log back in with their first name and date of birth? Super simple?

We also want anon users to be able to very easily 'upgrade' to a registered user, and keep whatever watch / progress they've completed in a course.

Permissions

In order, user permissions are:

1) Super Dev team / FA staff 2) Institute e.g. Melbourne University, or Tondo Foundation 3) Program e.g. Leave No-one Behind, or SCI2502 4) Teacher e.g. 2021 Summer socent course 5) Registered student 6) Guest student

Plus the weird, wonderful extra user: Researcher!

All admins have full view and edit access to everthing below their perm level.

Use cases

The weird and wonderful Researcher (TBC)

We'll implement this later coz is tricksy. Researchers exist outside of the typical 'school' structure, and can access anonymised, aggregate data at various levels.

This will be a delicately released feature, because it might expose lots of scary private data if we do it badly. There will probably be huge amounts of logging and tracking on who's seeing which data sets, and what they're doing with it.


Things to remember

For each user, the app should remember certain variables:

Last viewed/watched:

Other user preferences:

The above means that the app will attempt to find the preferred video and transcript language, and display that, or fall back to English.

This means a Cambodia user could choose an app language of KH, while watching videos in EN, with subtitles displayed in KH, and just for fun, transcripts in EN.

The above example has Khmer buttons, English spoken in the videos with Khmer subtitles, while reading transcripts happens in English. ARGH!


Translation

We translate the app at these levels:

English is our fallback language. If a 'preferred' language is unvailable, fall back to English. This means some parts of a lesson may or may not be transcribed.

Example: Partially translated lesson.

KH means Khmer, EN means English, PH means Tagolog:

Example user preferences:

The above might read as "I speak Khmer as a first language, but want to see subtitles and read transcripts in English, to improve my English."

Let's mash this against an example lesson with its translations:

Example translations available:


Will's foolish notes and design ideas:

Domains:

How to define future features

  1. Do a blog post with screen shots
  2. Show it to dev to see how hard it is
  3. Change blog post until people are happy
  4. Do wireframes in XD or paper
  5. ???

Add Youtube as a video type

Bits:

Day 1: Retro

Day 1.5: Ideas + snacks (together)

Day 3: Research + rethink (small group)

Day 4: Refine the scope

More stuff

Will, think about: