Desenvolupat prototip inicial

L'estructura del codi del backend està completa, caldrà anar
desenvolupant més codi però sota la mateixa estructura.

Aquest commit introdueix la implementació de l'inici de sessió amb
comptes de Google de la UPC i un mètode de l'API que retorna totes les
assignatures disponibles.
diff --git a/inc/API.php b/inc/API.php
new file mode 100644
index 0000000..0d5530e
--- /dev/null
+++ b/inc/API.php
@@ -0,0 +1,104 @@
+<?php
+namespace DAFME\Covid;
+
+class API {
+  private static function returnJSON($array) {
+    echo json_encode($array);
+  }
+
+  public static function returnError($errorMessage = 'Unexpected error') {
+    http_response_code(400);
+    self::returnJson([
+      'status' => 'error',
+      'errorMessage' =>  $errorMessage
+    ]);
+  }
+
+  public static function returnPayload($payload) {
+    self::returnJson([
+      'status' => 'ok',
+      'payload' => $payload
+    ]);
+  }
+
+  public static function returnOk() {
+    self::returnJson([
+      'status' => 'ok'
+    ]);
+  }
+
+  private static function checkSignInStatus() {
+    if (!Users::isSignedIn()) {
+      self::returnError('The user hasn\'t signed in.');
+      exit();
+    }    
+  }
+
+  public static function process($path) {
+    global $conf;
+
+    header('Content-Type: application/json');
+
+    if (isset($conf['frontendUrl']) && !empty($conf['frontendUrl']))
+      header('Access-Control-Allow-Origin: '.$conf['frontendUrl']);
+
+    $parts = explode('/', $path);
+    $method = $parts[0] ?? '';
+
+    switch ($method) {
+      case 'getAuthUrl':
+        $auth = new Auth();
+        self::returnPayload([
+          'url' => $auth->getAuthUrl()
+        ]);
+        break;
+
+      case 'isSignedIn':
+        $isSignedIn = \DAFME\Covid\Users::isSignedIn();
+        self::returnPayload([
+          'signedIn' => $isSignedIn
+        ]);
+        break;
+
+      case 'signOut':
+        \DAFME\Covid\Users::signOut();
+        self::returnOk();
+        break;
+
+      case 'getAllSubjects':
+        $subjects = Subjects::getAll();
+
+        if ($subjects === false)
+          self::returnError();
+
+        self::returnPayload([
+          'subjects' => $subjects
+        ]);
+        break;
+
+      case 'getUserSubjects':
+        self::checkSignInStatus();
+        // @TODO: Implement this method
+        break;
+
+      case 'setUserSubjects':
+        self::checkSignInStatus();
+        // @TODO: Implement this method
+        break;
+
+      case 'getClasses':
+        self::checkSignInStatus();
+        // @TODO: Implement this method
+        break;
+
+      case 'setClassState':
+        self::checkSignInStatus();
+        // @TODO: Handle this method
+        break;
+
+      default:
+        self::returnError('The method requested doesn\'t exist.');
+        break;
+    }
+  }
+}
diff --git a/inc/Auth.php b/inc/Auth.php
new file mode 100644
index 0000000..c0fc078
--- /dev/null
+++ b/inc/Auth.php
@@ -0,0 +1,59 @@
+<?php
+namespace DAFME\Covid;
+
+class Auth {
+  private $client;
+
+  public function __construct() {
+    global $conf;
+    $this->client = new \Google_Client();
+    $this->client->setApplicationName = 'dafme-covid-tracability-backend';
+    $this->client->setClientId($conf['goog']['clientId']);
+    $this->client->setClientSecret($conf['goog']['secret']);
+    $this->client->addScope('https://www.googleapis.com/auth/userinfo.email');
+    $this->client->setRedirectUri($conf['fullPath'].'oauth2callback.php');
+    $this->client->setAccessType('online');
+  }
+
+  public function getAuthUrl() {
+    return $this->client->createAuthUrl();
+  }
+
+  public function handleCallback() {
+    global $_GET, $con;
+    if (isset($_GET['error']) || !isset($_GET['code'])) return 1;
+
+    $accessToken = null;
+
+    try {
+      $accessToken = $this->client->fetchAccessTokenWithAuthCode($_GET['code']);
+    } catch (\Exception $exception) {
+      return 2;
+    }
+
+    $id = $this->client->verifyIdToken();
+    if ($id === false)
+      return 3;
+
+    if (!isset($id['sub']) || !isset($id['email']) || !isset($id['email_verified']))
+      return 4;
+
+    if ($id['email_verified'] === false)
+      return 5;
+
+    $sub = $id['sub'];
+    $email = $id['email'];
+
+    if (preg_match('/upc.edu$/', $id['email']) !== 1)
+      return 6;
+
+    if (!Users::signIn($sub, $email))
+      return 7;
+
+    return 0;
+  }
+
+  public function setAccessToken($token) {
+    $this->client->setAccessToken($token);
+  }
+}
diff --git a/inc/Subjects.php b/inc/Subjects.php
new file mode 100644
index 0000000..4d2cfdb
--- /dev/null
+++ b/inc/Subjects.php
@@ -0,0 +1,14 @@
+<?php
+namespace DAFME\Covid;
+
+class Subjects {
+  public static function getAll() {
+    global $con;
+    $query = $con->prepare('SELECT * FROM subjects');
+
+    if (!$query->execute())
+      return false;
+
+    return $query->fetchAll(\PDO::FETCH_ASSOC);
+  }
+}
diff --git a/inc/Users.php b/inc/Users.php
new file mode 100644
index 0000000..7679e04
--- /dev/null
+++ b/inc/Users.php
@@ -0,0 +1,51 @@
+<?php
+namespace DAFME\Covid;
+
+class Users {
+  private static function getUserId($sub) {
+    global $con;
+    $query = $con->prepare('SELECT id FROM users WHERE sub = ?');
+    if (!$query->execute([$sub]))
+      return false;
+
+    if ($query->rowCount() < 1)
+      return false;
+
+    $row = $query->fetch();
+    return $row['id'] ?? false;
+  }
+
+  public static function add($sub, $email) {
+    global $con;
+    $query = $con->prepare('INSERT INTO users (sub, email) VALUES (?, ?)');
+    if (!$query->execute([$sub, $email]))
+      return false;
+
+    return $con->lastInsertId();
+  }
+
+  public static function signIn($sub, $email) {
+    global $_SESSION;
+
+    $userId = self::getUserId($sub);
+
+    if ($userId === false)
+      $userId = self::add($sub, $email);
+
+    if ($userId === false)
+      return false;
+
+    $_SESSION['userId'] = $userId;
+    return true;
+  }
+
+  public static function signOut() {
+    global $_SESSION;
+    unset($_SESSION['userId']);
+  }
+
+  public static function isSignedIn() {
+    global $_SESSION;
+    return isset($_SESSION['userId']);
+  }
+}