[![Build Status](https://travis-ci.org/mumuki/mumuki-laboratory.svg?branch=master)](https://travis-ci.org/mumuki/mumuki-laboratory)
[![Code Climate](https://codeclimate.com/github/mumuki/mumuki-laboratory/badges/gpa.svg)](https://codeclimate.com/github/mumuki/mumuki-laboratory)
[![Test Coverage](https://codeclimate.com/github/mumuki/mumuki-laboratory/badges/coverage.svg)](https://codeclimate.com/github/mumuki/mumuki-laboratory)
[![Issue Count](https://codeclimate.com/github/mumuki/mumuki-laboratory/badges/issue_count.svg)](https://codeclimate.com/github/mumuki/mumuki-laboratory)
# Mumuki Laboratory [![btn_donate_lg](https://cloud.githubusercontent.com/assets/1039278/16535119/386d7be2-3fbb-11e6-9ee5-ecde4cef142a.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KCZ5AQR53CH26)
> Code assement web application for the Mumuki Platform
## About
Laboratory is a multitenant Rails webapp for solving exercises, organized in terms of chapters and guides.
## Preparing environment
### 1. Install essentials and base libraries
> First, we need to install some software: [PostgreSQL](https://www.postgresql.org) database, [RabbitMQ](https://www.rabbitmq.com/) queue, and some common Ruby on Rails native dependencies
```bash
sudo apt-get install autoconf curl git build-essential libssl-dev autoconf bison libreadline6 libreadline6-dev zlib1g zlib1g-dev postgresql libpq-dev rabbitmq-server
```
### 2. Install rbenv
> [rbenv](https://github.com/rbenv/rbenv) is a ruby versions manager, similar to rvm, nvm, and so on.
```bash
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
```
### 3. Install ruby
> Now we have rbenv installed, we can install ruby and [bundler](http://bundler.io/)
```bash
rbenv install 2.3.1
rbenv global 2.3.1
rbenv rehash
gem install bundler
```
### 4. Clone this repository
> Because, err... we need to clone this repostory before developing it :stuck_out_tongue:
```bash
git clone https://github.com/mumuki/mumuki-laboratory
cd mumuki-laboratory
```
### 5. Install and setup database
> We need to create a PostgreSQL role - AKA a user - who will be used by Laboratory to create and access the database
```bash
# create db user for linux users
sudo -u postgres psql <`.
Before using the API, take a look to the roles hierarchy:
![roles hierarchy](https://yuml.me/diagram/plain/class/[Owner]%5E-[Janitor],%20[Janitor]%5E-[Headmaster],%20[Headmaster]%5E-[Teacher],%20[Teacher]%5E-[Student],%20,%20[Owner]%5E-[Editor],%20[Editor]%5E-[Writer]).
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 `/`, 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/_`
* owner: `_/_`
### Users
#### Create single user
This is a generic user creation request.
**Minimal permission**: `janitor`
```
POST /users
```
Sample request body:
```json
{
"first_name": "María",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"permissions": {
"student": "cpt/*:rte/*",
"teacher": "ppp/2016-2q"
}
}
```
#### Update single user
This is a way of updating user basic data. Permissions are ignored.
**Minimal permission**: `janitor`
```
PUT /users/:uid
```
Sample request body:
```json
{
"first_name": "María",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"uid": "maryK345@foobar.edu.ar"
}
```
#### Add student to course
Creates the student if necessary, and updates her permissions.
**Minimal permission**: `janitor`
```
POST /courses/:organization/:course/students
```
```json
{
"first_name": "María",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar",
"uid": "maryK345@foobar.edu.ar"
}
```
**Response**
```json
{
"uid": "maryK345@foobar.edu.ar",
"first_name": "María",
"last_name": "Casas",
"email": "maryK345@foobar.edu.ar"
}
```
**Forbidden Response**
```json
{
"status": 403,
"error": "Exception"
}
```
#### Detach student from course
Remove student permissions from a course.
**Minimal permission**: `janitor`
```
POST /courses/:organization/:course/students/:uid/detach
```
**Response**: status code: 200
**Not Found Response**
```json
{
"status": 404,
"error": "Couldn't find User"
}
```
#### Attach student to course
Add student permissions to a course.
**Minimal permission**: `janitor`
```
POST /courses/:organization/:course/students/:uid/attach
```
**Response**: status code: 200
**Not Found Response**
```json
{
"status": 404,
"error": "Couldn't find User"
}
```
#### Add teacher to course
Creates the teacher if necessary, and updates her permissions.
**Minimal permission**: `headmaster`, `janitor`
```
POST /course/:id/teachers
```
```json
{
"first_name": "Erica",
"last_name": "Gonzalez",
"email": "egonzalez@foobar.edu.ar",
"uid": "egonzalez@foobar.edu.ar"
}
```
#### Add a batch of users to a course
Creates every user if necesssary, an updates permissions.
**Minimal permission**: `janitor`
```
POST /course/:id/batches
```
```json
{
"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"
}
]
}
```
#### Detach student from course
**Minimal permission**: `janitor`
```
DELETE /course/:id/students/:uid
```
#### Detach teacher from course
**Minimal permission**: `janitor`
```
DELETE /course/:id/teachers/:uid
```
#### Destroy single user
**Minimal permission**: `owner`
```
DELETE /users/:uid
```
### Courses
#### Create single course
**Minimal permission**: `janitor`
```
POST /organization/:id/courses/
```
```json
{
"name":"....",
}
```
#### Archive single course
**Minimal permission**: `janitor`
```
DELETE /organization/:id/courses/:id
```
#### Destroy single course
**Minimal permission**: `owner`
```
DELETE /courses/:id
```
### Organizations
#### Model
### Mandatory fields
```json
{
"name": "academy",
"contact_email": "issues@mumuki.io",
"books": [
"MumukiProject/mumuki-libro-metaprogramacion"
],
"locale": "es-AR"
}
```
### Optional fields
```json
{
"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` to `public`, `login_methods`, the values will be `false` and `["user_pass"].
- If you set `null` to `description`, the value will be `null`.
- If you set `null` to the others, it will be inherited from an organization called `"base"` every time you query the API.
### Generated fields
```json
{
"theme_stylesheet_url": "stylesheets/academy-asjdf92j1jd8.css",
"extension_javascript_url": "javascripts/academy-jd912j8jdj19.js"
}
```
#### List all organizations
```
get /organizations
```
Sample response body:
```json
{
"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 single organization by name
```
get /organizations/:name
```
Sample response body:
```json
{ "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.
#### Create organization
```
post /organizations
```
... with at least the required fields.
**Minimal permission**: `owner` of that organization
#### Update organization
```
put /organizations/:name
```
... with a partial update.
**Minimal permission**: `owner` of `:name`
## Authentication Powered by Auth0