Code assement web application for the Mumuki Platform
Laboratory is a multitenant Rails webapp for solving exercises, organized in terms of chapters and guides.
First, we need to install some software: PostgreSQL database, RabbitMQ queue, and some common Ruby on Rails native dependencies
sudo apt-get install autoconf curl git build-essential libssl-dev autoconf bison libreadline6 libreadline6-dev zlib1g zlib1g-dev postgresql libpq-dev rabbitmq-server
rbenv is a ruby versions manager, similar to rvm, nvm, and so on.
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc # or .bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bashrc # or .bash_profile
Now we have rbenv installed, we can install ruby and bundler
rbenv install 2.3.1
rbenv global 2.3.1
rbenv rehash
gem install bundler
Because, err... we need to clone this repostory before developing it đ
git clone https://github.com/mumuki/mumuki-laboratory
cd mumuki-laboratory
We need to create a PostgreSQL role - AKA a user - who will be used by Laboratory to create and access the database
# create db user for linux users
sudo -u postgres psql <<EOF
create role mumuki with createdb login password 'mumuki';
EOF
# create db user for mac users
psql postgres
#once inside postgres server
create role mumuki with createdb login password 'mumuki';
# create schema and initial development data
./devinit
If you want to start the server quickly in developer environment, you can just do the following:
./devstart
This will install your dependencies and boot the server.
If you just want to install dependencies, just do:
bundle install
You can boot the server by using the standard rackup command:
# using defaults from config/puma.rb and rackup default port 9292
bundle exec rackup
# changing port
bundle exec rackup -p 8080
# changing threads count
MUMUKI_LABORATORY_THREADS=30 bundle exec rackup
# changing workers count
MUMUKI_LABORATORY_WORKERS=4 bundle exec rackup
Or you can also start it with puma
command, which gives you more control:
# using defaults from config/puma.rb
bundle exec puma
# changing ports, workers and threads count, using puma-specific options:
bundle exec puma -w 4 -t 2:30 -p 8080
# changing ports, workers and threads count, using environment variables:
MUMUKI_LABORATORY_WORKERS=4 MUMUKI_LABORATORY_PORT=8080 MUMUKI_LABORATORY_THREADS=30 bundle exec puma
Finally, you can also start your server using rails
:
rails s
bundle exec rspec
In order to be customized by runners, Laboratory exposes the following selectors and methods which are granted to be safe and stable.
.mu-final-state
.mu-initial-state-header
.mu-initial-state
.mu-kids-blocks
.mu-kids-context
.mu-kids-exercise-description
.mu-kids-exercise
.mu-kids-reset-button
.mu-kids-results-aborted
.mu-kids-results
.mu-kids-state-image
.mu-kids-state
.mu-kids-states
.mu-kids-submit-button
.mu-multiple-scenarios
.mu-scenarios
#mu-actual-state-text
#mu-custom-editor-default-value
#mu-custom-editor-extra
#mu-custom-editor-test
#mu-custom-editor-value
#mu-initial-state-text
.mu-kids-gbs-board-initial
: Use.mu-initial-state
instead.mu-state-final
: Use.mu-final-state
instead.mu-state-initial
: Use.mu-initial-state
instead#kids-context
: Use.mu-kids-context
instead#kids-results-aborted
: Use.mu-kids-results-aborted
instead#kids-results
: Use.mu-kids-results
instead
mumuki.bridge.Laboratory
.runTests
mumuki.kids
registerBlocksAreaScaler
registerStateScaler
restart
scaleBlocksArea
scaleState
showResult
mumuki.locale
mumuki.MultipleScenarios
scenarios
currentScenarioIndex
resetIndicators
updateIndicators
mumuki.multipleFileEditor
setUpAddFile
setUpDeleteFiles
setUpDeleteFile
updateButtonsVisibility
mumuki.version
- Laboratory Kids API Initialization
- Runner Editor JS
- Laboratory Kids Layout Initialization
- Runner Editor HTML
In order to be able to link content, laboratory exposes slug-based routes that will redirect to the actual content URL in the current organization transparently:
GET <organization-url>/topics/<organization>/<repository>
GET <organization-url>/guides/<organization>/<repository>
GET <organization-url>/exercises/<organization>/<repository>/<bibliotheca-id>
Before using the API, you must create an ApiClient
using rails c
, which will generate a private JWT. Use it to authenticate API calls in any Platform application within a Authorizaion: Bearer <TOKEN>
.
Before using the API, take a look to the roles hierarchy:
Permissions are bound to a scope, that states in which context the operation can be performed. Scopes are simply two-level contexts, expressed as slugss <first>/<second>
, without any explicit semantic. They exact meaning depends on the role:
- student:
organization/course
- teacher and headmaster:
organization/course
- writer and editor:
organization/content
- janitor:
organization/_
- moderator:
organization/_
- owner:
_/_
This is a generic user creation request.
Minimal permission: janitor
POST /users
Sample request body:
{
"first_name": "MarĂa",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"permissions": {
"student": "cpt/*:rte/*",
"teacher": "ppp/2016-2q"
}
}
This is a way of updating user basic data. Permissions are ignored.
Minimal permission: janitor
PUT /users/:uid
Sample request body:
{
"first_name": "MarĂa",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"uid": "maryK345@foobar.edu.ar"
}
Creates the student if necessary, and updates her permissions.
Minimal permission: janitor
POST /courses/:organization/:course/students
{
"first_name": "MarĂa",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"uid": "maryK345@foobar.edu.ar"
}
Response
{
"uid": "maryK345@foobar.edu.ar",
"first_name": "MarĂa",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar"
}
Forbidden Response
{
"status": 403,
"error": "Exception"
}
Remove student permissions from a course.
Minimal permission: janitor
POST /courses/:organization/:course/students/:uid/detach
Response: status code: 200
Not Found Response
{
"status": 404,
"error": "Couldn't find User"
}
Add student permissions to a course.
Minimal permission: janitor
POST /courses/:organization/:course/students/:uid/attach
Response: status code: 200
Not Found Response
{
"status": 404,
"error": "Couldn't find User"
}
Creates the teacher if necessary, and updates her permissions.
Minimal permission: headmaster
, janitor
POST /course/:id/teachers
{
"first_name": "Erica",
"last_name": "Gonzalez",
"email": "egonzalez@foobar.edu.ar",
"uid": "egonzalez@foobar.edu.ar"
}
Creates every user if necesssary, an updates permissions.
Minimal permission: janitor
POST /course/:id/batches
{
"students": [
{
"first_name": "Tupac",
"last_name": "Lincoln",
"email": "tliconln@foobar.edu.ar",
"uid": "tliconln@foobar.edu.ar"
}
],
"teachers": [
{
"first_name": "Erica",
"last_name": "Gonzalez",
"email": "egonzalez@foobar.edu.ar",
"uid": "egonzalez@foobar.edu.ar"
}
]
}
Minimal permission: janitor
DELETE /course/:id/students/:uid
Minimal permission: janitor
DELETE /course/:id/teachers/:uid
Minimal permission: owner
DELETE /users/:uid
Minimal permission: janitor
POST /organization/:id/courses/
{
"name":"....",
}
Minimal permission: janitor
DELETE /organization/:id/courses/:id
Minimal permission: owner
DELETE /courses/:id
{
"name": "academy",
"contact_email": "issues@mumuki.io",
"books": [
"MumukiProject/mumuki-libro-metaprogramacion"
],
"locale": "es-AR"
}
{
"public": false,
"description": "...",
"login_methods": [
"facebook", "twitter", "google"
],
"logo_url": "http://mumuki.io/logo-alt-large.png",
"terms_of_service": "Al usar Mumuki aceptĂĄs que las soluciones de tus ejercicios sean registradas para ser corregidas por tu/s docente/s...",
"theme_stylesheet": ".theme { color: red }",
"extension_javascript": "doSomething = function() { }"
}
- If you set
null
topublic
,login_methods
, the values will befalse
and `["user_pass"]. - If you set
null
todescription
, the value will benull
. - If you set
null
to the others, it will be inherited from an organization called"base"
every time you query the API.
{
"theme_stylesheet_url": "stylesheets/academy-asjdf92j1jd8.css",
"extension_javascript_url": "javascripts/academy-jd912j8jdj19.js"
}
get /organizations
Sample response body:
{
"organizations": [
{ "name": "academy", "contact_email": "a@a.com", "locale": "es-AR", "login_methods": ["facebook"], "books": ["libro"], "public": true, "logo_url":"http://..." },
{ "name": "alcal", "contact_email": "b@b.com", "locale": "en-US", "login_methods": ["facebook", "github"], "books": ["book"], "public": false }
]
}
Minimal permission: None for public organizations, janitor
for user's private organizations.
get /organizations/:name
Sample response body:
{ "name": "academy", "contact_email": "a@a.com", "locale": "es-AR", "login_methods": ["facebook"], "books": ["libro"], "public": true, "logo_url":"http://..." }
Minimal permission: janitor
of the organization.
post /organizations
... with at least the required fields.
Minimal permission: owner
of that organization
put /organizations/:name
... with a partial update.
Minimal permission: owner
of :name