Skip to content

Commit

Permalink
Merge: SQL
Browse files Browse the repository at this point in the history
![1dan1m](https://cloud.githubusercontent.com/assets/1444825/19865386/650afce4-9f72-11e6-8e49-5152e7f5f2ed.jpg)

Big PR here, this should make the transition from a MongoDB model to the famed SQL model.
The code base being large, there might be some parts of the application that might break, but from the last checks I did, most of the app should work.
Some parts, like achievements may need a bit of an overhaul to make it production-ready, but the base is here.

Note: I know the login redirect is semi-broken, I'll check to fix it, in the meantime, you are more than encouraged to take a look at the code :)

<!-- Reviewable:start -->

---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/morriar/missions/158)
<!-- Reviewable:end -->

Pull-Request: #158
Reviewed-by: Jean Privat <[email protected]>
Reviewed-by: Alexandre Terrasa <[email protected]>
Reviewed-by: Istvan SZALAÏ <[email protected]>
  • Loading branch information
Jenkins Gresil committed Dec 6, 2016
2 parents caca34c + 39d1390 commit 305fc35
Show file tree
Hide file tree
Showing 51 changed files with 2,264 additions and 1,028 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM nitlang/nit

# Needed for nitcorn and to build mongo-c-driver
RUN apt-get update && apt-get install -y libevent-dev libssl-dev libsasl2-dev libcurl4-openssl-dev file
RUN apt-get update && apt-get install -y libevent-dev libssl-dev libsasl2-dev libcurl4-openssl-dev file libsqlite3-dev sqlite3

# Install mongo-c-driver manually since it is not available in Debian/jessie
RUN curl -L https://github.com/mongodb/mongo-c-driver/releases/download/1.4.0/mongo-c-driver-1.4.0.tar.gz -o mongo-c-driver-1.4.0.tar.gz \
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ bin/db_loader:
nitserial src/db_loader.nit -o src/db_loader_serial.nit
nitc src/db_loader.nit -m src/db_loader_serial.nit -o bin/db_loader

populate: bin/db_loader
populate: bin/db_loader init_db
# There are levels to this... try: `make populate level=2`
bin/db_loader $(level)

init_db:
sqlite3 Missions < init.sql

run:
bin/app --auth shib

Expand Down
211 changes: 211 additions & 0 deletions init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
DROP TABLE IF EXISTS players;
DROP TABLE IF EXISTS friends;
DROP TABLE IF EXISTS category;
DROP TABLE IF EXISTS tracks;
DROP TABLE IF EXISTS missions;
DROP TABLE IF EXISTS mission_dependencies;
DROP TABLE IF EXISTS testcases;
DROP TABLE IF EXISTS stars;
DROP TABLE IF EXISTS track_status;
DROP TABLE IF EXISTS mission_status;
DROP TABLE IF EXISTS star_status;
DROP TABLE IF EXISTS events;
DROP TABLE IF EXISTS submissions;
DROP TABLE IF EXISTS friend_events;
DROP TABLE IF EXISTS achievements;
DROP TABLE IF EXISTS notifications;
DROP TABLE IF EXISTS achievement_unlocks;
DROP TABLE IF EXISTS languages;
DROP TABLE IF EXISTS track_languages;
DROP TABLE IF EXISTS mission_languages;
DROP TABLE IF EXISTS track_statuses;
DROP TABLE IF EXISTS star_results;


CREATE TABLE players(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
name TEXT DEFAULT "",
email TEXT DEFAULT "",
avatar_url TEXT DEFAULT "",
date_joined INTEGER NOT NULL
);

CREATE TABLE friends(
player_id1 INTEGER,
player_id2 INTEGER,

PRIMARY KEY(player_id1, player_id2),
FOREIGN KEY(player_id1) REFERENCES players(id),
FOREIGN KEY(player_id2) REFERENCES players(id)
);

CREATE TABLE languages(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT
);

CREATE TABLE tracks(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
description TEXT DEFAULT "",
path TEXT
);

CREATE TABLE track_languages(
track_id INTEGER,
language_id INTEGER,

PRIMARY KEY(track_id, language_id),
FOREIGN KEY(track_id) REFERENCES tracks(id),
FOREIGN KEY(language_id) REFERENCES languages(id)
);

CREATE TABLE track_statuses(
track_id INTEGER,
player_id INTEGER,
status INTEGER,

PRIMARY KEY(track_id, player_id),
FOREIGN KEY(track_id) REFERENCES tracks(id),
FOREIGN KEY(player_id) REFERENCES players(id)
);

CREATE TABLE missions(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
track_id INTEGER NOT NULL,
description TEXT NOT NULL,
reward INTEGER DEFAULT 0,
path TEXT,

FOREIGN KEY(track_id) REFERENCES tracks(id)
);

CREATE TABLE mission_languages(
mission_id INTEGER,
language_id INTEGER,

PRIMARY KEY(mission_id, language_id),
FOREIGN KEY (mission_id) REFERENCES missions(id),
FOREIGN KEY (language_id) REFERENCES languages(id)
);

CREATE TABLE mission_dependencies(
mission_id INTEGER NOT NULL,
parent_id INTEGER NOT NULL,
PRIMARY KEY (mission_id, parent_id),

FOREIGN KEY(mission_id) REFERENCES missions(id),
FOREIGN KEY(parent_id) REFERENCES missions(id)
);

CREATE TABLE testcases(
id INTEGER PRIMARY KEY AUTOINCREMENT,
mission_id INTEGER NOT NULL,
root_uri TEXT NOT NULL,

FOREIGN KEY(mission_id) REFERENCES missions(id)
);

CREATE TABLE stars(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
mission_id INTEGER NOT NULL,
score INTEGER DEFAULT 0,
reward INTEGER DEFAULT 0,
type_id INTEGER NOT NULL,

FOREIGN KEY(mission_id) REFERENCES missions(id)
);

CREATE TABLE mission_status(
mission_id INTEGER,
player_id INTEGER,
status INTEGER NOT NULL,
PRIMARY KEY(mission_id, player_id),

FOREIGN KEY(mission_id) REFERENCES missions(id),
FOREIGN KEY(player_id) REFERENCES players(id)
);

CREATE TABLE star_status(
star_id INTEGER,
player_id INTEGER,
status BOOLEAN DEFAULT FALSE,
PRIMARY KEY(star_id, player_id),

FOREIGN KEY(star_id) REFERENCES stars(id),
FOREIGN KEY(player_id) REFERENCES players(id)
);

CREATE TABLE events(
id INTEGER PRIMARY KEY AUTOINCREMENT,
datetime INTEGER NOT NULL
);

CREATE TABLE submissions(
event_id INTEGER PRIMARY KEY,
player_id INTEGER NOT NULL,
mission_id TEXT NOT NULL,
workspace_path TEXT,
status INTEGER DEFAULT 1,

FOREIGN KEY(event_id) REFERENCES events(id),
FOREIGN KEY(player_id) REFERENCES players(id),
FOREIGN KEY(mission_id) REFERENCES missions(id)
);

CREATE TABLE friend_events(
event_id INTEGER PRIMARY KEY,
player_id1 INTEGER NOT NULL,
player_id2 INTEGER NOT NULL,
status INTEGER DEFAULT 0,

FOREIGN KEY(event_id) REFERENCES events(id),
FOREIGN KEY(player_id1) REFERENCES players(id),
FOREIGN KEY(player_id2) REFERENCES players(id)
);

CREATE TABLE achievements(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
description TEXT,
reward INTEGER DEFAULT 0
);

CREATE TABLE achievement_unlocks(
event_id INTEGER PRIMARY KEY,
achievement_id INTEGER,
player_id INTEGER,

FOREIGN KEY(event_id) REFERENCES events(id),
FOREIGN KEY(player_id) REFERENCES players(id),
FOREIGN KEY(achievement_id) REFERENCES achievements(id)
);

CREATE TABLE notifications(
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id INTEGER NOT NULL,
player_id INTEGER NOT NULL,
object TEXT NOT NULL,
body TEXT DEFAULT "",
read BOOLEAN DEFAULT FALSE,
timestamp INTEGER NOT NULL,

FOREIGN KEY(event_id) REFERENCES events(id),
FOREIGN KEY(player_id) REFERENCES players(id)
);

CREATE TABLE star_results(
id INTEGER PRIMARY KEY AUTOINCREMENT,
submission_id INTEGER NOT NULL,
star_id INTEGER NOT NULL,
score INTEGER NOT NULL,

FOREIGN KEY(submission_id) REFERENCES submissions(event_id),
FOREIGN KEY(star_id) REFERENCES stars(id)
);
10 changes: 5 additions & 5 deletions misc/setup_pep.nit
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import model::loader
import submissions
import api

var opts = new AppOptions.from_args(args)
var config = new AppConfig.from_options(opts)
var config = new AppConfig
config.parse_options(args)

# clean bd
config.db.drop
Expand All @@ -31,7 +31,7 @@ for mission in config.missions.find_all do
print " no path. skip"
continue
end

# Get a potential solution
var f = (path / "solution.pep").to_path
var source = f.read_all
Expand All @@ -55,8 +55,8 @@ for mission in config.missions.find_all do
# If success, update the goals in the original .ini file
if sub.status == "success" then
var ini = new ConfigTree((path / "config.ini").to_s)
ini["star.time_goal"] = sub.time_score.to_s
ini["star.size_goal"] = sub.size_score.to_s
ini["star.time_goal"] = (sub.time_score or else "").to_s
ini["star.size_goal"] = (sub.size_score or else "").to_s
ini.save
end
end
4 changes: 4 additions & 0 deletions src/api/api.nit
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import api::api_tracks
import api::api_missions
import api::api_achievements

redef class AppConfig
redef init do super # FIXME avoid linearization conflit
end

redef class AuthRouter
redef init do super # FIXME avoid linearization conflit
end
Expand Down
6 changes: 3 additions & 3 deletions src/api/api_achievements.nit
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class APIAchievements
super APIHandler

redef fun get(req, res) do
res.json new JsonArray.from(config.achievements.group_achievements)
res.json new JsonArray.from(req.ctx.all_achievements)
end
end

Expand All @@ -43,7 +43,7 @@ class APIAchievement
res.api_error("Missing URI param `aid`", 400)
return null
end
var achievement = config.achievements.find_by_key(aid)
var achievement = req.ctx.achievement_by_slug(aid)
if achievement == null then
res.api_error("Achievement `{aid}` not found", 404)
return null
Expand All @@ -64,6 +64,6 @@ class APIAchievementPlayers
redef fun get(req, res) do
var achievement = get_achievement(req, res)
if achievement == null then return
res.json new JsonArray.from(achievement.players(config))
res.json new JsonArray.from(achievement.players)
end
end
40 changes: 21 additions & 19 deletions src/api/api_auth.nit
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,30 @@ redef class AppConfig
# Authentification method used
#
# At this point can be either `github` or `shib`, see the clients modules.
var auth_methods: Array[String] is lazy do return value_or_default("auth", default_auth_method).split(",")
fun auth_methods: Array[String] do return (ini["auth"] or else default_auth_method).split(",")

# Default authentification method used
#
# Will be refined based on what auth method we implement.
fun default_auth_method: String is abstract

redef init from_options(opts) do
super
var auth_methods = opts.opt_auth_method.value
if not auth_methods.is_empty then
self["auth"] = auth_methods.join(",")
end
end
end

redef class AppOptions

# Authentification to use
#
# Can be either `github` or `shib`.
var opt_auth_method = new OptionArray("Authentification service to use. Can be `github` (default) and/or `shib`", "--auth")

init do
redef init do
super
add_option(opt_auth_method)
end

redef fun parse_options(opts) do
super
var auth_methods = opt_auth_method.value
if not auth_methods.is_empty then
ini["auth"] = auth_methods.join(",")
end
end
end

# The common auth router
Expand Down Expand Up @@ -81,7 +78,7 @@ class SessionRefresh
if session == null then return
var player = session.player
if player == null then return
session.player = config.players.find_by_id(player.id)
session.player = req.ctx.player_by_id(player.id)
end
end

Expand Down Expand Up @@ -117,8 +114,14 @@ abstract class AuthLogin
# Helper method to use when a new account is created.
fun register_new_player(player: Player)
do
player.add_achievement(config, new FirstLoginAchievement(player))
config.players.save player
var ctx = player.context
var first_login = ctx.achievement_by_slug("hello_world")
if first_login == null then
first_login = new FirstLoginAchievement(ctx)
first_login.commit
end
player.add_achievement(first_login)
player.commit
end

# Redirect to the `next` page.
Expand Down Expand Up @@ -149,6 +152,7 @@ class AuthHandler
res.api_error("Unauthorized", 403)
return null
end
player.context = req.ctx
return player
end
end
Expand All @@ -175,11 +179,9 @@ end
class FirstLoginAchievement
super Achievement
serialize
autoinit player
autoinit(context)

redef var key = "first_login"
redef var title = "Hello World!"
redef var desc = "Login into the mission board for the first time."
redef var reward = 10
redef var icon = "log-in"
end
Loading

0 comments on commit 305fc35

Please sign in to comment.