Afegits mètodes de l'API per configurar assignatures

D'aquesta manera els alumnes poden configurar la llista d'assignatures
que cursen.

Change-Id: I40d1b47918f0cc2b19b08b7682ce955beebfd8bd
diff --git a/inc/API.php b/inc/API.php
index ccc2c94..8891a68 100644
--- a/inc/API.php
+++ b/inc/API.php
@@ -4,6 +4,7 @@
 class API {
   private static function returnJSON($array) {
     echo json_encode($array);
+    exit();
   }
 
   public static function returnError($errorMessage = 'Unexpected error') {
@@ -30,10 +31,21 @@
   private static function checkSignInStatus() {
     if (!Users::isSignedIn()) {
       self::returnError('The user hasn\'t signed in.');
-      exit();
     }    
   }
 
+  private static function getJSONBody() {
+    if ($_SERVER['REQUEST_METHOD'] !== 'POST')
+      self::returnError('This action requires using the POST method.');
+
+    $rawBody = file_get_contents('php://input');
+    $json = json_decode($rawBody, true);
+    if (json_last_error() !== JSON_ERROR_NONE)
+      self::returnError('The request body is malformed.');
+
+    return $json;
+  }
+
   public static function process($path) {
     global $conf;
 
@@ -78,10 +90,41 @@
 
       case 'getUserSubjects':
         self::checkSignInStatus();
-        // @TODO: Implement this method
+        $subjects = Subjects::getUserSubjects();
+
+        if ($subjects === false)
+          self::returnError();
+
+        self::returnPayload([
+          'subjects' => $subjects
+        ]);
         break;
 
-      case 'setUserSubjects':
+      case 'addUserSubject':
+        self::checkSignInStatus();
+        $body = self::getJSONBody();
+        if (!isset($body['subject']))
+          self::returnError();
+
+        if (Subjects::addUserSubject((int)$body['subject']))
+          self::returnOk();
+        else
+          self::returnError();
+        break;
+
+      case 'removeUserSubject':
+        self::checkSignInStatus();
+        $body = self::getJSONBody();
+        if (!isset($body['subject']))
+          self::returnError();
+
+        if (Subjects::removeUserSubject((int)$body['subject']))
+          self::returnOk();
+        else
+          self::returnError();
+        break;
+
+      case 'removeUserSubject':
         self::checkSignInStatus();
         // @TODO: Implement this method
         break;
diff --git a/inc/Subjects.php b/inc/Subjects.php
index 4d2cfdb..1578398 100644
--- a/inc/Subjects.php
+++ b/inc/Subjects.php
@@ -11,4 +11,71 @@
 
     return $query->fetchAll(\PDO::FETCH_ASSOC);
   }
+
+  public static function exists(int $subject): bool {
+    global $con;
+    $query = $con->prepare('SELECT id FROM subjects WHERE id = ?');
+    if (!$query->execute([$subject]))
+      return false;
+
+    return $query->rowCount() > 0;
+  }
+
+  public static function isNewUserSubject(int $subjectId): bool {
+    global $con;
+    $query = $con->prepare('SELECT id FROM user_subjects WHERE user_id = :user_id AND subject_id = :subject_id');
+
+    $userId = Users::getUserId();
+    if ($userId == -1 || !$query->execute([
+      'user_id' => $userId,
+      'subject_id' => $subjectId
+    ]))
+      return false;
+
+    return $query->rowCount() == 0;
+  }
+
+  public static function getUserSubjects() {
+    global $con;
+    $query = $con->prepare('SELECT
+        us.id, us.subject_id, s.friendly_name, s.calendar_name
+        FROM user_subjects us
+        INNER JOIN subjects s
+          ON us.subject_id = s.id
+        WHERE us.user_id = ?');
+
+    $userId = Users::getUserId();
+    if ($userId == -1 || !$query->execute([$userId]))
+      return false;
+
+    return $query->fetchAll(\PDO::FETCH_ASSOC);
+  }
+
+  public static function addUserSubject(int $subjectId): bool {
+    global $con;
+
+    if (!self::exists($subjectId) || !self::isNewUserSubject($subjectId))
+      return false;
+
+    $query = $con->prepare('INSERT INTO user_subjects (user_id, subject_id) VALUES (:user_id, :subject_id)');
+
+    $userId = Users::getUserId();
+
+    return $userId != -1 && $query->execute([
+      'user_id' => $userId,
+      'subject_id' => $subjectId
+    ]);
+  }
+
+  public static function removeUserSubject(int $subjectId): bool {
+    global $con;
+
+    $query = $con->prepare('DELETE FROM user_subjects WHERE user_id = :user_id AND subject_id = :subject_id LIMIT 1');
+
+    $userId = Users::getUserId();
+    return $userId != -1 && $query->execute([
+      'user_id' => $userId,
+      'subject_id' => $subjectId
+    ]);
+  }
 }
diff --git a/inc/Users.php b/inc/Users.php
index 7679e04..b91737f 100644
--- a/inc/Users.php
+++ b/inc/Users.php
@@ -2,7 +2,7 @@
 namespace DAFME\Covid;
 
 class Users {
-  private static function getUserId($sub) {
+  private static function getUserIdFromSub($sub) {
     global $con;
     $query = $con->prepare('SELECT id FROM users WHERE sub = ?');
     if (!$query->execute([$sub]))
@@ -15,7 +15,7 @@
     return $row['id'] ?? false;
   }
 
-  public static function add($sub, $email) {
+  public static function add($sub, $email): int {
     global $con;
     $query = $con->prepare('INSERT INTO users (sub, email) VALUES (?, ?)');
     if (!$query->execute([$sub, $email]))
@@ -24,10 +24,10 @@
     return $con->lastInsertId();
   }
 
-  public static function signIn($sub, $email) {
+  public static function signIn($sub, $email): bool {
     global $_SESSION;
 
-    $userId = self::getUserId($sub);
+    $userId = self::getUserIdFromSub($sub);
 
     if ($userId === false)
       $userId = self::add($sub, $email);
@@ -39,13 +39,18 @@
     return true;
   }
 
-  public static function signOut() {
+  public static function signOut(): void {
     global $_SESSION;
     unset($_SESSION['userId']);
   }
 
-  public static function isSignedIn() {
+  public static function isSignedIn(): bool {
     global $_SESSION;
     return isset($_SESSION['userId']);
   }
+
+  public static function getUserId(): int {
+    global $_SESSION;
+    return (self::isSignedIn() ? $_SESSION['userId'] : -1);
+  }
 }