Skip to content
Open

SQL #158

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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