diff --git a/Documentation/README.md b/Documentation/README.md
index a4f81fc6..af30a432 100644
--- a/Documentation/README.md
+++ b/Documentation/README.md
@@ -1,195 +1,195 @@
-# Development Notes
-
-- [Backend Structure](#backend-structure)
-- [Frontend Structure](#frontend-structure)
-- [Administration Structure](#administration-structure)
-
-# Backend Structure
-
-The main components we are going to dive in are:
-- Controllers
-- Extra Fields
-- Filtration
-- Encryption
-
-## Controllers
-
-Each table has a custom controller by which each have their own methods.
-The main controller to look at is the Application Controller.
-
-This controller contains all methods used for the Extra Fields as well as helper methods for other controllers to deny or permit accesd to users and paginate extra fields.
-
-These are explicitly documented inside the code to make it easy to find and follow.
-
-An example of what you can find in the Application Controller:
-
-```ruby
- # UTILS
-
- # Returns a ```UserRole``` entry for the currently existing admin role.
- def get_admin_role
- return UserRole.where(name: "eduapp-admin").first
- end
-
- # Returns the user's respective ```UserRole``` information.
- def get_user_roles(user_id = @current_user)
- return UserRole.find(UserInfo.where(user_id: user_id).first.user_role_id)
- end
-
- # Serializes each element in an array.
- def serialize_each(array, iExcept = [], iInclude = [])
- s = []
- array.each do |item|
- s.push(item.serializable_hash(except: iExcept, include: iInclude))
- end
- return s
- end
-
- # Paginates an ```ActiveRecord``` query.
- def query_paginate(query, page, limit = 10)
- page = Integer(page)
- if page - 1 < 0
- return { :error => "Page cannot be less than 1" }
- end
- return { :current_page => query.limit(limit).offset((page - 1) * limit), :total_pages => (query.count.to_f / limit).ceil, :page => page }
- end
-
- # Paginates an array.
- def array_paginate(array, page, limit = 10)
- return array.slice(Integer(page) > 0 ? Integer(page) - 1 : 0, limit)
- end
-
- # A parser made to correctly return a decoded order filter.
- def parse_filter_order(order)
- order = JSON.parse(Base64.decode64(order))
- return { order["field"] => order["order"] == "asc" ? :asc : :desc }
- end
-```
-
-## Extra Fields
-
-Extra fields are made to provide access to custom information each Institution needs. Examples of this can be student debts, detention counts and custom notes.
-
-The tables elegible for extra fields are Users, Courses, Sessions, Institutions, Resources and Subjects.
-
-Helper methods for these are located as well in the Application Controller.
-
-## Filtration
-
-Each controller has it's own way of filtrating. Every controller follows a pattern:
-
-- Check if any extra fields exists and try to filter by that
-- If there's any filtered extra fields, filter with that by the other main fields, if not, filter by any value in the database.
-- Order by ascending if no order is specified
-- Return the first page if not page of information is specified
-
-## Encryption
-
-EduApp has it's own encryption utility inside ```lib/edu_app_utils/encrypt_utils.rb```.
-
-Here, you will find different methods used to encrypt and decrypt messages for the messaging part of EduApp.
-
-# Frontend Structure
-
-The main topics we will cover about how the frontend works:
-- It's PWA
- - How we save information offline
-- It's different utilities
-- Custom hooks
-
-## The PWA
-
-The PWA has two main components necessary:
-- ```service-worker.js```
-- ```serviceWorkerRegistration.js```
-
-These two components are necessary for registering the Service Worker to the browser so that it works correctly.
-
-This all depends on WorkBox to register and save to browser cache the compiled assets necessary to run the app.
-
-To save the user's important information for offline use, we use the ```OfflineManager.js``` utility. This helps us saving and updating any information when needed so that we have always the most updated user information at all types.
-
-## Utilities
-
-The different types of utilities we use are:
-- ```OfflineManager```
-- ```IDBManager```
-- ```MediaFixer```
-- ```FirebaseStorage```
-- ```UrlPrefixer```
-- ActionCable websockets
-
-### OfflineManager
-
-The offline manager contains various functions used to save and load information for further use when in offline mode.
-
-The workflow used is to always store information offline when received from the API, and if the information is different then save it, if not there's no need to save it.
-
-```getOfflineUser()``` is the main function you will want to use for accessing a user's information online or offline. It all depends on the information in it.
-
-### IDBManager
-
-The IDBManager uses a library @jakearchibald called ```idb-keyval``` which converts all IndexedDB functions into asynchronous, for ease of use.
-
-The class contains methods used as a Singleton to load a store and make transactions.
-
-### MediaFixer
-
-MediaFixer is a small function used to correct files from Rails ActiveStorage from not displaying the correct URL. It changes the ```localhost:3000``` domain that ActiveStorage sets to the back domain passed inside the ```.env``` file.
-
-### FirebaseStorage
-
-This is used to upload any files used to a Firebase Storage bucket in case ActiveStorage fails. As of now, only profile images are uploaded to Firebase.
-
-### UrlPrefixer
-
-This is used in case you change your domains base name to a new mount point.
-
-Example: default - eduapp.com
-Changed basename: eduapp.com/app
-
-This functions converts all urls passed to use the new basename you specify. This was previously used for ease of use, but it's not necessary anymore.
-
-### ActionCable Websockets
-
-Rails ActionCable needs a special JS library from the same developers to connect to each other.
-
-To provide an easy interface, we created a class called ```ACManager``` which is an abstract class used to create new Websocket classes to manage the different websocket channels in the backend.
-
-
-# Administration Structure
-
-The main topics we will cover:
-
-- Initialization of the administration panel and database
-- Login
-- Components
-
-## Initialization
-
-When creating and intializing the backend, frontend and administration for the first time, you will be prompted to create a new administrator user. Once done, you may login with your new administration account.
-
-Once in, you will only be able to see to sections:
-- Institutions
-- User Permissions/Roles
-
-To unlock the other administrative sections, you must first create your an Institution. Once created, you may access the other sections to setup your educational environment.
-
-## Login
-
-Only users who have an ```admin-query``` or ```admin``` role are able to have access to the web app by default. You may change this inside the authentication service inside ```services```.
-
-## Components
-
-The administration panel constitutes of one main parent view with rotating child components. This means that ControlPanel is the parent view that never changes, and the only components that change are the inside/body of the main page.
-
-Each component behaves differently since they all manage different sets of data according to their table, but they share common features:
-- Creation
-- Deletion
-- Updates
-- Filtration
-- Extra Fields
-- Extra Fields Filtration
-- Order By
-
-Chat messages are not displayed to manage to keep the users privacy safe.
+# Development Notes
+
+- [Backend Structure](#backend-structure)
+- [Frontend Structure](#frontend-structure)
+- [Administration Structure](#administration-structure)
+
+# Backend Structure
+
+The main components we are going to dive in are:
+- Controllers
+- Extra Fields
+- Filtration
+- Encryption
+
+## Controllers
+
+Each table has a custom controller by which each have their own methods.
+The main controller to look at is the Application Controller.
+
+This controller contains all methods used for the Extra Fields as well as helper methods for other controllers to deny or permit accesd to users and paginate extra fields.
+
+These are explicitly documented inside the code to make it easy to find and follow.
+
+An example of what you can find in the Application Controller:
+
+```ruby
+ # UTILS
+
+ # Returns a ```UserRole``` entry for the currently existing admin role.
+ def get_admin_role
+ return UserRole.where(name: "eduapp-admin").first
+ end
+
+ # Returns the user's respective ```UserRole``` information.
+ def get_user_roles(user_id = @current_user)
+ return UserRole.find(UserInfo.where(user_id: user_id).first.user_role_id)
+ end
+
+ # Serializes each element in an array.
+ def serialize_each(array, iExcept = [], iInclude = [])
+ s = []
+ array.each do |item|
+ s.push(item.serializable_hash(except: iExcept, include: iInclude))
+ end
+ return s
+ end
+
+ # Paginates an ```ActiveRecord``` query.
+ def query_paginate(query, page, limit = 10)
+ page = Integer(page)
+ if page - 1 < 0
+ return { :error => "Page cannot be less than 1" }
+ end
+ return { :current_page => query.limit(limit).offset((page - 1) * limit), :total_pages => (query.count.to_f / limit).ceil, :page => page }
+ end
+
+ # Paginates an array.
+ def array_paginate(array, page, limit = 10)
+ return array.slice(Integer(page) > 0 ? Integer(page) - 1 : 0, limit)
+ end
+
+ # A parser made to correctly return a decoded order filter.
+ def parse_filter_order(order)
+ order = JSON.parse(Base64.decode64(order))
+ return { order["field"] => order["order"] == "asc" ? :asc : :desc }
+ end
+```
+
+## Extra Fields
+
+Extra fields are made to provide access to custom information each Institution needs. Examples of this can be student debts, detention counts and custom notes.
+
+The tables elegible for extra fields are Users, Courses, Sessions, Institutions, Resources and Subjects.
+
+Helper methods for these are located as well in the Application Controller.
+
+## Filtration
+
+Each controller has it's own way of filtrating. Every controller follows a pattern:
+
+- Check if any extra fields exists and try to filter by that
+- If there's any filtered extra fields, filter with that by the other main fields, if not, filter by any value in the database.
+- Order by ascending if no order is specified
+- Return the first page if not page of information is specified
+
+## Encryption
+
+EduApp has it's own encryption utility inside ```lib/edu_app_utils/encrypt_utils.rb```.
+
+Here, you will find different methods used to encrypt and decrypt messages for the messaging part of EduApp.
+
+# Frontend Structure
+
+The main topics we will cover about how the frontend works:
+- It's PWA
+ - How we save information offline
+- It's different utilities
+- Custom hooks
+
+## The PWA
+
+The PWA has two main components necessary:
+- ```service-worker.js```
+- ```serviceWorkerRegistration.js```
+
+These two components are necessary for registering the Service Worker to the browser so that it works correctly.
+
+This all depends on WorkBox to register and save to browser cache the compiled assets necessary to run the app.
+
+To save the user's important information for offline use, we use the ```OfflineManager.js``` utility. This helps us saving and updating any information when needed so that we have always the most updated user information at all types.
+
+## Utilities
+
+The different types of utilities we use are:
+- ```OfflineManager```
+- ```IDBManager```
+- ```MediaFixer```
+- ```FirebaseStorage```
+- ```UrlPrefixer```
+- ActionCable websockets
+
+### OfflineManager
+
+The offline manager contains various functions used to save and load information for further use when in offline mode.
+
+The workflow used is to always store information offline when received from the API, and if the information is different then save it, if not there's no need to save it.
+
+```getOfflineUser()``` is the main function you will want to use for accessing a user's information online or offline. It all depends on the information in it.
+
+### IDBManager
+
+The IDBManager uses a library @jakearchibald called ```idb-keyval``` which converts all IndexedDB functions into asynchronous, for ease of use.
+
+The class contains methods used as a Singleton to load a store and make transactions.
+
+### MediaFixer
+
+MediaFixer is a small function used to correct files from Rails ActiveStorage from not displaying the correct URL. It changes the ```localhost:3000``` domain that ActiveStorage sets to the back domain passed inside the ```.env``` file.
+
+### FirebaseStorage
+
+This is used to upload any files used to a Firebase Storage bucket in case ActiveStorage fails. As of now, only profile images are uploaded to Firebase.
+
+### UrlPrefixer
+
+This is used in case you change your domains base name to a new mount point.
+
+Example: default - eduapp.com
+Changed basename: eduapp.com/app
+
+This functions converts all urls passed to use the new basename you specify. This was previously used for ease of use, but it's not necessary anymore.
+
+### ActionCable Websockets
+
+Rails ActionCable needs a special JS library from the same developers to connect to each other.
+
+To provide an easy interface, we created a class called ```ACManager``` which is an abstract class used to create new Websocket classes to manage the different websocket channels in the backend.
+
+
+# Administration Structure
+
+The main topics we will cover:
+
+- Initialization of the administration panel and database
+- Login
+- Components
+
+## Initialization
+
+When creating and intializing the backend, frontend and administration for the first time, you will be prompted to create a new administrator user. Once done, you may login with your new administration account.
+
+Once in, you will only be able to see to sections:
+- Institutions
+- User Permissions/Roles
+
+To unlock the other administrative sections, you must first create your an Institution. Once created, you may access the other sections to setup your educational environment.
+
+## Login
+
+Only users who have an ```admin-query``` or ```admin``` role are able to have access to the web app by default. You may change this inside the authentication service inside ```services```.
+
+## Components
+
+The administration panel constitutes of one main parent view with rotating child components. This means that ControlPanel is the parent view that never changes, and the only components that change are the inside/body of the main page.
+
+Each component behaves differently since they all manage different sets of data according to their table, but they share common features:
+- Creation
+- Deletion
+- Updates
+- Filtration
+- Extra Fields
+- Extra Fields Filtration
+- Order By
+
+Chat messages are not displayed to manage to keep the users privacy safe.
diff --git a/Documentation/old-readme.txt b/Documentation/old-readme.txt
index adb3aab8..bbc597de 100644
--- a/Documentation/old-readme.txt
+++ b/Documentation/old-readme.txt
@@ -1,313 +1,313 @@
-
- Eduapp emerges after the covid 19 pandemic, as the answer to the challenges that this entails.
-
-
- It's an european project, co-funded by erasmus+ programme
-
-
Partners
-
Fundatia Ecologica Green - Romania, Instituto Politécnico de Santarém - Portugal, Stichting Landstede - Netherlands, SOSU OSTJYLLAND - Denmark and IES El Rincón - Spain
-
Objectives
-
Faciliate and increase the communication between school, students and teachers by developing an application, EduApp, free and open source, customised for each partner school.
-
-
-
Backend information
-
Eduapp has used postgresQL as database, ruby on rails as server-side web application framework.
After using these commands, you need to look inside the config folder and find the database.yml. There, you must change the database password and put your postgreSQL password, otherwise, the database will not work.
-
-
To have elegible data in the database, enter the following commands:
-
-```bash
-rails db:create
-rails db:migrate:reset // Used to restart all database values
-```
-
-
After you have followed these steps, you can start the server with:
-
-```bash
-rails s
-```
-
-
To stop the server you have to use CTRL + C.
-
Frontend information:
-
This is how eduapp started but some visual changes were made.
-
-Prototype
-
-
-
-
-
-
-
-
How to install and run
-
First, you must install the programs. Now you have to clone the project and used this commands.
-
To clone, use:
-
-```bash
-git clone https://github.com/eduappdevs/eduapp
-cd eduapp/frontend
-npm install
-
-// For Windows users
-npm run start-win
-
-// For Unix system users (Mac, Linux)
-npm run start-unix
-```
-
-
We have used orange and blue as principal colors , then we use a different gray scales and white.
-
After an intensive search we have found the perfect combination with orange and blue as principal colors, combined with a bolder font weight.
-
-
In the sign up form , we have added a advisor in the passwords fields , which gives you feedback if the password it's empty or the confirmation password does not match with the previously written password.
-
-
-
-
Before the password its written and the confirmation password matches , you aren't able to sign up the account and the submit button were disabled , after the confirmation matches it will be enabled and you can submit and sign up the account.
-
This is the function which checks if the password it is empty or the confirmation password matches with the previously password field.
This app has implemented a full responsiveness, with individual development for mobile and desktop
-
In desktop , this is how it looks sign up form:
-
-
Mobile view
-
Here you can see how the navbar looks , with icon buttons in the bottom of the page becouse it is more easier to users.
-
-
We have decided to change the styles of the navbar buttons, choosing a transparent background, the buttons have a default blue background if you are not in that location, if you click in that button this will change to orange to give you feedback about where you are.
-
Before/After
-
-
-
-
-
Desktop view
-
Here you can see how the navbar looks, placed at the top of the page, the reason why we have decided to change that is becouse in a desktop environment it is more common to see the navbar at the top and text in the buttons instead of icons.
-
-
Eduapp have a dark mode
-
The reason why we have decided to implement a dark mode it is becouse in the last time it is very common to see in all the apps.
-
A dark mode gives you a comfortable experience in situation where the light it is dark, otherwise you force your eyes to see the screen, although this were uncomfortable.
-
-
-
Then the page looks like this
-
-
-
Loading animation
-
When page were loading , an animation will be on screen.
-
This it's a frame of it , this hole animation was created in pure css.
-
This gives you feedback when something is loading.
-
-
-
Tech stack and comparison
-
In our case , currently we are developing EduApp as a web app , using a full responsiveness , but we like to make it downloadable ,
-making eduapp as a hybrid app.
-
-We are using react js as frontend framework , react provides us many advantages , such an easier learning, reusable components, ReactJS is choosing by most developers, becouse it provide us a very rich JavaScript library
-
-At backend we have decide to use Ruby on rails , which provide us a Model View Controller architecture , a fast development when you know the basics of it ,
-a great number of helpful tools and libraries , also it haves many disadvantages , like the price of a mistake , you have to pay attention to all the small details ,otherwise your ruby on rails journey will becomes difficult.
-
-
Docker Mounting
-
-Mounting to docker is easy, but we need to make some adjustment to Ruby on Rails first.
-To start off, you must clone the branch called "docker-config" which has been previously prepared for straight docker composing.
-Before mounting to docker, please look into each ```Dockerfile``` and modify your environment variables to your need.
-
-Once configured environment variables, run ```docker-compose up -d``` inside the root directory to mount and start the database, backend api, frontend interface and administration panel once the mounting completes.
-If you wish to mount only the backend, frontend, or administration panel, make sure you position yourself inside the corresponding directory and run the command above, to mount only the corresponding docker-compose.
-
-Once finished mounting, you must access the API container shell and run the following command to create and migrate the database:
-
-```
-rails db:create
-rails db:migrate:reset
-```
-
-And you will have successfully mounted and deployed EduApp to multiple docker containers!
-
-
Personal opinion and conclusions
-
It is a pleasure to us be part of this project , as our first project working in with other people,becoming this project a challenge , we found many difficults in the journey, but we also have learned so much through it,although this it is just the beggining of the project and so much things will happen through the journey.
+ Eduapp emerges after the covid 19 pandemic, as the answer to the challenges that this entails.
+
+
+ It's an european project, co-funded by erasmus+ programme
+
+
Partners
+
Fundatia Ecologica Green - Romania, Instituto Politécnico de Santarém - Portugal, Stichting Landstede - Netherlands, SOSU OSTJYLLAND - Denmark and IES El Rincón - Spain
+
Objectives
+
Faciliate and increase the communication between school, students and teachers by developing an application, EduApp, free and open source, customised for each partner school.
+
+
+
Backend information
+
Eduapp has used postgresQL as database, ruby on rails as server-side web application framework.
After using these commands, you need to look inside the config folder and find the database.yml. There, you must change the database password and put your postgreSQL password, otherwise, the database will not work.
+
+
To have elegible data in the database, enter the following commands:
+
+```bash
+rails db:create
+rails db:migrate:reset // Used to restart all database values
+```
+
+
After you have followed these steps, you can start the server with:
+
+```bash
+rails s
+```
+
+
To stop the server you have to use CTRL + C.
+
Frontend information:
+
This is how eduapp started but some visual changes were made.
+
+Prototype
+
+
+
+
+
+
+
+
How to install and run
+
First, you must install the programs. Now you have to clone the project and used this commands.
+
To clone, use:
+
+```bash
+git clone https://github.com/eduappdevs/eduapp
+cd eduapp/frontend
+npm install
+
+// For Windows users
+npm run start-win
+
+// For Unix system users (Mac, Linux)
+npm run start-unix
+```
+
+
We have used orange and blue as principal colors , then we use a different gray scales and white.
+
After an intensive search we have found the perfect combination with orange and blue as principal colors, combined with a bolder font weight.
+
+
In the sign up form , we have added a advisor in the passwords fields , which gives you feedback if the password it's empty or the confirmation password does not match with the previously written password.
+
+
+
+
Before the password its written and the confirmation password matches , you aren't able to sign up the account and the submit button were disabled , after the confirmation matches it will be enabled and you can submit and sign up the account.
+
This is the function which checks if the password it is empty or the confirmation password matches with the previously password field.
This app has implemented a full responsiveness, with individual development for mobile and desktop
+
In desktop , this is how it looks sign up form:
+
+
Mobile view
+
Here you can see how the navbar looks , with icon buttons in the bottom of the page becouse it is more easier to users.
+
+
We have decided to change the styles of the navbar buttons, choosing a transparent background, the buttons have a default blue background if you are not in that location, if you click in that button this will change to orange to give you feedback about where you are.
+
Before/After
+
+
+
+
+
Desktop view
+
Here you can see how the navbar looks, placed at the top of the page, the reason why we have decided to change that is becouse in a desktop environment it is more common to see the navbar at the top and text in the buttons instead of icons.
+
+
Eduapp have a dark mode
+
The reason why we have decided to implement a dark mode it is becouse in the last time it is very common to see in all the apps.
+
A dark mode gives you a comfortable experience in situation where the light it is dark, otherwise you force your eyes to see the screen, although this were uncomfortable.
+
+
+
Then the page looks like this
+
+
+
Loading animation
+
When page were loading , an animation will be on screen.
+
This it's a frame of it , this hole animation was created in pure css.
+
This gives you feedback when something is loading.
+
+
+
Tech stack and comparison
+
In our case , currently we are developing EduApp as a web app , using a full responsiveness , but we like to make it downloadable ,
+making eduapp as a hybrid app.
+
+We are using react js as frontend framework , react provides us many advantages , such an easier learning, reusable components, ReactJS is choosing by most developers, becouse it provide us a very rich JavaScript library
+
+At backend we have decide to use Ruby on rails , which provide us a Model View Controller architecture , a fast development when you know the basics of it ,
+a great number of helpful tools and libraries , also it haves many disadvantages , like the price of a mistake , you have to pay attention to all the small details ,otherwise your ruby on rails journey will becomes difficult.
+
+
Docker Mounting
+
+Mounting to docker is easy, but we need to make some adjustment to Ruby on Rails first.
+To start off, you must clone the branch called "docker-config" which has been previously prepared for straight docker composing.
+Before mounting to docker, please look into each ```Dockerfile``` and modify your environment variables to your need.
+
+Once configured environment variables, run ```docker-compose up -d``` inside the root directory to mount and start the database, backend api, frontend interface and administration panel once the mounting completes.
+If you wish to mount only the backend, frontend, or administration panel, make sure you position yourself inside the corresponding directory and run the command above, to mount only the corresponding docker-compose.
+
+Once finished mounting, you must access the API container shell and run the following command to create and migrate the database:
+
+```
+rails db:create
+rails db:migrate:reset
+```
+
+And you will have successfully mounted and deployed EduApp to multiple docker containers!
+
+
Personal opinion and conclusions
+
It is a pleasure to us be part of this project , as our first project working in with other people,becoming this project a challenge , we found many difficults in the journey, but we also have learned so much through it,although this it is just the beggining of the project and so much things will happen through the journey.
diff --git a/backend/eduapp_db/.env-example-development b/backend/eduapp_db/.env-example-development
new file mode 100644
index 00000000..de805f26
--- /dev/null
+++ b/backend/eduapp_db/.env-example-development
@@ -0,0 +1,38 @@
+# RAILS
+# Do not modify unless you know what you are doing.
+RAILS_SECRET_KEY=599fef69235287bd8c268db895897f236aebf4f63971aa48f48e3ee81c5612006a4857751cb1859546ccde67bb84cb3cc799a6aa9196b036d9a872dcd7765809
+ENCRYPTION_SALT="81IJngXK2FE1+1J2Ugs1VxuK0yTnUyZQCSFbv0SUNRgZpMN7EN8SzoeSDuD+\nOXU0cwQyoFaAgfsckvz0di4SIyxHZs0OWey32Y5VI6Dg8rTNR8q2Z+oIv4tS\n2DOYeQ56uax3nQ/A+JikqvsLAfZYjhe3OpB5GUlgeJFnA30xB68Ock3HSInI\nW1kuZxN8dQu2eGwPT+3iNR9/DHe0Zku3G5MtZNzciHAT04JXVP+YXVraLVv1\nj5ctdDmWx1shNoBidO3q6PS+0peInRJmChVHcfoaBbhQuF2hv5vv5Qcd/c0f\nUDOWqho2DrA3hYm252t5BWTjfNoI3p7M0E1KRHmZDQ==\n"
+ENCRYPTION_PATTERN="#_::_#"
+
+RAILS_ENV=development
+API_VERSION="v1"
+
+# POSTGRES CONFIG
+# This needs to match the 'postgres.docker-example.env' configured variables.
+DEV_DB_USER="eduapp_user"
+DEV_DB_PSWD="custom-password-1234"
+DEV_DB_PORT="5432" # Do not touch.
+
+# HOSTING CONFIG
+# Do not touch. This is internal.
+PORT=3010
+DB_HOST=db # WITH DOCKER
+HOST="localhost" # DEVELOPMENT
+DOMAIN="localhost" # DEVELOPMENT
+
+# FRONTEND ENPOINT FOR CORS
+# It is important for your domain/url not to end with '/', as
+# the CORS policy won't detect it an forbid you from entering
+# Localhost example:
+REACT_APP_FRONTEND_ENDPOINT=http://localhost:8443
+REACT_APP_ADMIN_ENDPOINT=http://localhost:4010
+
+
+# EMAIL
+# Do not touch. This is internal.
+SMTP_PORT=587
+SMTP_ADDRESS=smtp.gmail.com
+# If you wish to use a different email for sending
+# emails to users, change it here.
+GMAIL_USERNAME=youremail@gmail.com
+GMAIL_PASSWORD=yourpassword
\ No newline at end of file
diff --git a/backend/eduapp_db/.env-example-production b/backend/eduapp_db/.env-example-production
new file mode 100644
index 00000000..53bd4373
--- /dev/null
+++ b/backend/eduapp_db/.env-example-production
@@ -0,0 +1,37 @@
+# RAILS
+# Do not modify unless you know what you are doing.
+RAILS_SECRET_KEY=599fef69235287bd8c268db895897f236aebf4f63971aa48f48e3ee81c5612006a4857751cb1859546ccde67bb84cb3cc799a6aa9196b036d9a872dcd7765809
+ENCRYPTION_SALT="81IJngXK2FE1+1J2Ugs1VxuK0yTnUyZQCSFbv0SUNRgZpMN7EN8SzoeSDuD+\nOXU0cwQyoFaAgfsckvz0di4SIyxHZs0OWey32Y5VI6Dg8rTNR8q2Z+oIv4tS\n2DOYeQ56uax3nQ/A+JikqvsLAfZYjhe3OpB5GUlgeJFnA30xB68Ock3HSInI\nW1kuZxN8dQu2eGwPT+3iNR9/DHe0Zku3G5MtZNzciHAT04JXVP+YXVraLVv1\nj5ctdDmWx1shNoBidO3q6PS+0peInRJmChVHcfoaBbhQuF2hv5vv5Qcd/c0f\nUDOWqho2DrA3hYm252t5BWTjfNoI3p7M0E1KRHmZDQ==\n"
+ENCRYPTION_PATTERN="#_::_#"
+
+RAILS_ENV=production
+API_VERSION="v1"
+
+# POSTGRES CONFIG
+# This needs to match the 'postgres.docker-example.env' configured variables.
+PROD_DB_USER="eduapp_user"
+PROD_DB_PSWD="custom-password-1234"
+PROD_DB_PORT="5432" # Do not touch.
+
+# HOSTING CONFIG
+# Do not touch. This is internal.
+PORT=3010
+DB_HOST=db # WITH DOCKER
+
+HOST=your-backend-domain
+DOMAIN=your-backend-domain
+
+# FRONTEND ENPOINT FOR CORS
+# It is important for your domain/url not to end with '/', as
+# the CORS policy won't detect it an forbid you from entering
+REACT_APP_FRONTEND_ENDPOINT=https://your-frontend-domain:port
+REACT_APP_ADMIN_ENDPOINT=https://your-admin-domain:port
+
+# EMAIL
+# Do not touch. This is internal.
+SMTP_PORT=587
+SMTP_ADDRESS=smtp.gmail.com
+# If you wish to use a different email for sending
+# emails to users, change it here.
+GMAIL_USERNAME=youremail@gmail.com
+GMAIL_PASSWORD=yourpassword
\ No newline at end of file
diff --git a/backend/eduapp_db/.gitattributes b/backend/eduapp_db/.gitattributes
index dff662b5..13801c4a 100644
--- a/backend/eduapp_db/.gitattributes
+++ b/backend/eduapp_db/.gitattributes
@@ -1,8 +1,8 @@
-# See https://git-scm.com/docs/gitattributes for more about git attribute files.
-
-# Mark the database schema as having been generated.
-db/schema.rb linguist-generated
-
-
-# Mark any vendored files as having been vendored.
-vendor/* linguist-vendored
+# See https://git-scm.com/docs/gitattributes for more about git attribute files.
+
+# Mark the database schema as having been generated.
+db/schema.rb linguist-generated
+
+
+# Mark any vendored files as having been vendored.
+vendor/* linguist-vendored
diff --git a/backend/eduapp_db/.gitignore b/backend/eduapp_db/.gitignore
index b02e7b78..2086282b 100644
--- a/backend/eduapp_db/.gitignore
+++ b/backend/eduapp_db/.gitignore
@@ -1,32 +1,45 @@
-# See https://help.github.com/articles/ignoring-files for more about ignoring files.
-#
-# If you find yourself ignoring temporary files generated by your text editor
-# or operating system, you probably want to add a global ignore instead:
-# git config --global core.excludesfile '~/.gitignore_global'
-
-# Ignore bundler config.
-/.bundle
-/.cert
-
-# Ignore all logfiles and tempfiles.
-/log/*
-/tmp/*
-!/log/.keep
-!/tmp/.keep
-
-# Ignore pidfiles, but keep the directory.
-/tmp/pids/*
-!/tmp/pids/
-!/tmp/pids/.keep
-
-# Ignore uploaded files in development.
-/storage/*
-!/storage/.keep
-.byebug_history
-node_modules
-
-# Ignore master key for decrypting credentials and more.
-/config/master.key
-*.env
-!*docker-example.env
-.DS_Store
+# See https://help.github.com/articles/ignoring-files for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile '~/.gitignore_global'
+
+# Ignore bundler config.
+/.bundle
+/.cert
+
+# Ignore all logfiles and tempfiles.
+/log/*
+/tmp/*
+!/log/.keep
+!/tmp/.keep
+
+# Ignore pidfiles, but keep the directory.
+/tmp/pids/*
+!/tmp/pids/
+!/tmp/pids/.keep
+
+# Ignore uploaded files in development.
+/storage/*
+!/storage/.keep
+.byebug_history
+node_modules
+
+# Ignore master key for decrypting credentials and more.
+/config/master.key
+*.env
+!*docker-example.env
+.DS_Store
+
+config-velorcios
+
+.env-real-production
+.env-real-development
+
+dockerfile-real-production
+dockerfile-real-development
+
+dockerfile
+
+#Uploads files
+/public/uploads
diff --git a/backend/eduapp_db/.ruby-version b/backend/eduapp_db/.ruby-version
index 324db8d6..b19ea7ad 100644
--- a/backend/eduapp_db/.ruby-version
+++ b/backend/eduapp_db/.ruby-version
@@ -1 +1 @@
-ruby-2.6.8
+ruby-3.1.2
diff --git a/backend/eduapp_db/Gemfile b/backend/eduapp_db/Gemfile
index 00122609..a4db1866 100644
--- a/backend/eduapp_db/Gemfile
+++ b/backend/eduapp_db/Gemfile
@@ -1,33 +1,36 @@
-source "https://rubygems.org"
-git_source(:github) { |repo| "https://github.com/#{repo}.git" }
-
-ruby "2.6.8"
-# ruby "2.6.9" # Only to be used when building a docker image.
-
-gem "rails", "~> 6.1.4", ">= 6.1.4.1"
-gem "pg", "~> 1.1"
-gem "puma", "~> 5.0"
-gem "devise"
-gem "devise-jwt"
-gem "jwt"
-gem "openssl"
-gem "useragent"
-gem "dotenv-rails", :group => [:production, :development, :test]
-gem "rack-cors", :require => "rack/cors"
-gem "ransack"
-gem "image_processing", "~> 1.2"
-gem "active_model_serializers"
-gem "bootsnap", ">= 1.4.4", require: false
-gem "omniauth-rails_csrf_protection"
-gem "omniauth-google-oauth2"
-gem "omniauth"
-
-group :development, :test do
- gem "byebug", platforms: [:mri, :mingw, :x64_mingw]
-end
-
-group :test do
- gem "rspec-rails"
-end
-
-gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+source "https://rubygems.org"
+git_source(:github) { |repo| "https://github.com/#{repo}.git" }
+
+ruby "3.1.2"
+
+gem "rails", "~> 6.1.4", ">= 6.1.4.1"
+gem "pg", "~> 1.1"
+gem "puma", "~> 5.0"
+gem 'carrierwave'
+gem "devise"
+gem "devise-jwt"
+gem "jwt"
+gem "openssl"
+gem "useragent"
+gem "dotenv-rails", :group => [:production, :development, :test]
+gem "rack-cors", :require => "rack/cors"
+gem "ransack"
+gem 'rmagick'
+gem "image_processing", "~> 1.2"
+gem "active_model_serializers"
+gem "bootsnap", ">= 1.4.4", require: false
+gem "omniauth-rails_csrf_protection"
+gem "omniauth-google-oauth2"
+gem "omniauth"
+gem "net-smtp"
+gem "webpush"
+
+group :development, :test do
+ gem "byebug", platforms: [:mri, :mingw, :x64_mingw]
+end
+
+group :test do
+ gem "rspec-rails"
+end
+
+gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
diff --git a/backend/eduapp_db/Gemfile.lock b/backend/eduapp_db/Gemfile.lock
index f6628ff5..33fd01ec 100644
--- a/backend/eduapp_db/Gemfile.lock
+++ b/backend/eduapp_db/Gemfile.lock
@@ -1,280 +1,313 @@
-GEM
- remote: https://rubygems.org/
- specs:
- actioncable (6.1.6)
- actionpack (= 6.1.6)
- activesupport (= 6.1.6)
- nio4r (~> 2.0)
- websocket-driver (>= 0.6.1)
- actionmailbox (6.1.6)
- actionpack (= 6.1.6)
- activejob (= 6.1.6)
- activerecord (= 6.1.6)
- activestorage (= 6.1.6)
- activesupport (= 6.1.6)
- mail (>= 2.7.1)
- actionmailer (6.1.6)
- actionpack (= 6.1.6)
- actionview (= 6.1.6)
- activejob (= 6.1.6)
- activesupport (= 6.1.6)
- mail (~> 2.5, >= 2.5.4)
- rails-dom-testing (~> 2.0)
- actionpack (6.1.6)
- actionview (= 6.1.6)
- activesupport (= 6.1.6)
- rack (~> 2.0, >= 2.0.9)
- rack-test (>= 0.6.3)
- rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (6.1.6)
- actionpack (= 6.1.6)
- activerecord (= 6.1.6)
- activestorage (= 6.1.6)
- activesupport (= 6.1.6)
- nokogiri (>= 1.8.5)
- actionview (6.1.6)
- activesupport (= 6.1.6)
- builder (~> 3.1)
- erubi (~> 1.4)
- rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
- active_model_serializers (0.10.13)
- actionpack (>= 4.1, < 7.1)
- activemodel (>= 4.1, < 7.1)
- case_transform (>= 0.2)
- jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
- activejob (6.1.6)
- activesupport (= 6.1.6)
- globalid (>= 0.3.6)
- activemodel (6.1.6)
- activesupport (= 6.1.6)
- activerecord (6.1.6)
- activemodel (= 6.1.6)
- activesupport (= 6.1.6)
- activestorage (6.1.6)
- actionpack (= 6.1.6)
- activejob (= 6.1.6)
- activerecord (= 6.1.6)
- activesupport (= 6.1.6)
- marcel (~> 1.0)
- mini_mime (>= 1.1.0)
- activesupport (6.1.6)
- concurrent-ruby (~> 1.0, >= 1.0.2)
- i18n (>= 1.6, < 2)
- minitest (>= 5.1)
- tzinfo (~> 2.0)
- zeitwerk (~> 2.3)
- bcrypt (3.1.18)
- bootsnap (1.12.0)
- msgpack (~> 1.2)
- builder (3.2.4)
- byebug (11.1.3)
- case_transform (0.2)
- activesupport
- concurrent-ruby (1.1.10)
- crass (1.0.6)
- devise (4.8.1)
- bcrypt (~> 3.0)
- orm_adapter (~> 0.1)
- railties (>= 4.1.0)
- responders
- warden (~> 1.2.3)
- devise-jwt (0.9.0)
- devise (~> 4.0)
- warden-jwt_auth (~> 0.6)
- diff-lcs (1.5.0)
- dotenv (2.7.6)
- dotenv-rails (2.7.6)
- dotenv (= 2.7.6)
- railties (>= 3.2)
- dry-auto_inject (0.8.0)
- dry-container (>= 0.3.4)
- dry-configurable (0.13.0)
- concurrent-ruby (~> 1.0)
- dry-core (~> 0.6)
- dry-container (0.9.0)
- concurrent-ruby (~> 1.0)
- dry-configurable (~> 0.13, >= 0.13.0)
- dry-core (0.7.1)
- concurrent-ruby (~> 1.0)
- erubi (1.10.0)
- faraday (2.3.0)
- faraday-net_http (~> 2.0)
- ruby2_keywords (>= 0.0.4)
- faraday-net_http (2.0.3)
- ffi (1.15.5)
- ffi (1.15.5-x64-mingw32)
- globalid (1.0.0)
- activesupport (>= 5.0)
- hashie (5.0.0)
- i18n (1.10.0)
- concurrent-ruby (~> 1.0)
- image_processing (1.12.2)
- mini_magick (>= 4.9.5, < 5)
- ruby-vips (>= 2.0.17, < 3)
- jsonapi-renderer (0.2.2)
- jwt (2.3.0)
- loofah (2.18.0)
- crass (~> 1.0.2)
- nokogiri (>= 1.5.9)
- mail (2.7.1)
- mini_mime (>= 0.1.1)
- marcel (1.0.2)
- method_source (1.0.0)
- mini_magick (4.11.0)
- mini_mime (1.1.2)
- minitest (5.15.0)
- msgpack (1.5.2)
- multi_json (1.15.0)
- multi_xml (0.6.0)
- nio4r (2.5.8)
- nokogiri (1.13.6-x64-mingw32)
- racc (~> 1.4)
- nokogiri (1.13.6-x86_64-darwin)
- racc (~> 1.4)
- oauth2 (1.4.9)
- faraday (>= 0.17.3, < 3.0)
- jwt (>= 1.0, < 3.0)
- multi_json (~> 1.3)
- multi_xml (~> 0.5)
- rack (>= 1.2, < 3)
- omniauth (2.1.0)
- hashie (>= 3.4.6)
- rack (>= 2.2.3)
- rack-protection
- omniauth-google-oauth2 (1.0.1)
- jwt (>= 2.0)
- oauth2 (~> 1.1)
- omniauth (~> 2.0)
- omniauth-oauth2 (~> 1.7.1)
- omniauth-oauth2 (1.7.2)
- oauth2 (~> 1.4)
- omniauth (>= 1.9, < 3)
- omniauth-rails_csrf_protection (1.0.1)
- actionpack (>= 4.2)
- omniauth (~> 2.0)
- openssl (3.0.0)
- orm_adapter (0.5.0)
- pg (1.3.5)
- pg (1.3.5-x64-mingw32)
- puma (5.6.4)
- nio4r (~> 2.0)
- racc (1.6.0)
- rack (2.2.3.1)
- rack-cors (1.1.1)
- rack (>= 2.0.0)
- rack-protection (2.2.0)
- rack
- rack-test (1.1.0)
- rack (>= 1.0, < 3)
- rails (6.1.6)
- actioncable (= 6.1.6)
- actionmailbox (= 6.1.6)
- actionmailer (= 6.1.6)
- actionpack (= 6.1.6)
- actiontext (= 6.1.6)
- actionview (= 6.1.6)
- activejob (= 6.1.6)
- activemodel (= 6.1.6)
- activerecord (= 6.1.6)
- activestorage (= 6.1.6)
- activesupport (= 6.1.6)
- bundler (>= 1.15.0)
- railties (= 6.1.6)
- sprockets-rails (>= 2.0.0)
- rails-dom-testing (2.0.3)
- activesupport (>= 4.2.0)
- nokogiri (>= 1.6)
- rails-html-sanitizer (1.4.2)
- loofah (~> 2.3)
- railties (6.1.6)
- actionpack (= 6.1.6)
- activesupport (= 6.1.6)
- method_source
- rake (>= 12.2)
- thor (~> 1.0)
- rake (13.0.6)
- ransack (3.0.1)
- activerecord (>= 6.0.4)
- activesupport (>= 6.0.4)
- i18n
- responders (3.0.1)
- actionpack (>= 5.0)
- railties (>= 5.0)
- rspec-core (3.11.0)
- rspec-support (~> 3.11.0)
- rspec-expectations (3.11.0)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-mocks (3.11.1)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-rails (5.1.2)
- actionpack (>= 5.2)
- activesupport (>= 5.2)
- railties (>= 5.2)
- rspec-core (~> 3.10)
- rspec-expectations (~> 3.10)
- rspec-mocks (~> 3.10)
- rspec-support (~> 3.10)
- rspec-support (3.11.0)
- ruby-vips (2.1.4)
- ffi (~> 1.12)
- ruby2_keywords (0.0.5)
- sprockets (4.0.3)
- concurrent-ruby (~> 1.0)
- rack (> 1, < 3)
- sprockets-rails (3.4.2)
- actionpack (>= 5.2)
- activesupport (>= 5.2)
- sprockets (>= 3.0.0)
- thor (1.2.1)
- tzinfo (2.0.4)
- concurrent-ruby (~> 1.0)
- tzinfo-data (1.2022.1)
- tzinfo (>= 1.0.0)
- useragent (0.16.10)
- warden (1.2.9)
- rack (>= 2.0.9)
- warden-jwt_auth (0.6.0)
- dry-auto_inject (~> 0.8)
- dry-configurable (~> 0.13)
- jwt (~> 2.1)
- warden (~> 1.2)
- websocket-driver (0.7.5)
- websocket-extensions (>= 0.1.0)
- websocket-extensions (0.1.5)
- zeitwerk (2.5.4)
-
-PLATFORMS
- x64-mingw32
- x86_64-darwin-21
-
-DEPENDENCIES
- active_model_serializers
- bootsnap (>= 1.4.4)
- byebug
- devise
- devise-jwt
- dotenv-rails
- image_processing (~> 1.2)
- jwt
- omniauth
- omniauth-google-oauth2
- omniauth-rails_csrf_protection
- openssl
- pg (~> 1.1)
- puma (~> 5.0)
- rack-cors
- rails (~> 6.1.4, >= 6.1.4.1)
- ransack
- rspec-rails
- tzinfo-data
- useragent
-
-RUBY VERSION
- ruby 2.6.8p205
-
-BUNDLED WITH
- 2.3.6
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actioncable (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ nio4r (~> 2.0)
+ websocket-driver (>= 0.6.1)
+ actionmailbox (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ activejob (= 6.1.7.3)
+ activerecord (= 6.1.7.3)
+ activestorage (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ mail (>= 2.7.1)
+ actionmailer (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ actionview (= 6.1.7.3)
+ activejob (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 2.0)
+ actionpack (6.1.7.3)
+ actionview (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ rack (~> 2.0, >= 2.0.9)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
+ actiontext (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ activerecord (= 6.1.7.3)
+ activestorage (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ nokogiri (>= 1.8.5)
+ actionview (6.1.7.3)
+ activesupport (= 6.1.7.3)
+ builder (~> 3.1)
+ erubi (~> 1.4)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
+ active_model_serializers (0.10.13)
+ actionpack (>= 4.1, < 7.1)
+ activemodel (>= 4.1, < 7.1)
+ case_transform (>= 0.2)
+ jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
+ activejob (6.1.7.3)
+ activesupport (= 6.1.7.3)
+ globalid (>= 0.3.6)
+ activemodel (6.1.7.3)
+ activesupport (= 6.1.7.3)
+ activerecord (6.1.7.3)
+ activemodel (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ activestorage (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ activejob (= 6.1.7.3)
+ activerecord (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ marcel (~> 1.0)
+ mini_mime (>= 1.1.0)
+ activesupport (6.1.7.3)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 1.6, < 2)
+ minitest (>= 5.1)
+ tzinfo (~> 2.0)
+ zeitwerk (~> 2.3)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
+ bcrypt (3.1.18)
+ bootsnap (1.16.0)
+ msgpack (~> 1.2)
+ builder (3.2.4)
+ byebug (11.1.3)
+ carrierwave (2.2.3)
+ activemodel (>= 5.0.0)
+ activesupport (>= 5.0.0)
+ addressable (~> 2.6)
+ image_processing (~> 1.1)
+ marcel (~> 1.0.0)
+ mini_mime (>= 0.1.3)
+ ssrf_filter (~> 1.0)
+ case_transform (0.2)
+ activesupport
+ concurrent-ruby (1.2.2)
+ crass (1.0.6)
+ date (3.3.3)
+ devise (4.9.0)
+ bcrypt (~> 3.0)
+ orm_adapter (~> 0.1)
+ railties (>= 4.1.0)
+ responders
+ warden (~> 1.2.3)
+ devise-jwt (0.10.0)
+ devise (~> 4.0)
+ warden-jwt_auth (~> 0.6)
+ diff-lcs (1.5.0)
+ dotenv (2.8.1)
+ dotenv-rails (2.8.1)
+ dotenv (= 2.8.1)
+ railties (>= 3.2)
+ dry-auto_inject (1.0.1)
+ dry-core (~> 1.0)
+ zeitwerk (~> 2.6)
+ dry-configurable (1.0.1)
+ dry-core (~> 1.0, < 2)
+ zeitwerk (~> 2.6)
+ dry-core (1.0.0)
+ concurrent-ruby (~> 1.0)
+ zeitwerk (~> 2.6)
+ erubi (1.12.0)
+ faraday (2.7.4)
+ faraday-net_http (>= 2.0, < 3.1)
+ ruby2_keywords (>= 0.0.4)
+ faraday-net_http (3.0.2)
+ ffi (1.15.5)
+ globalid (1.1.0)
+ activesupport (>= 5.0)
+ hashie (5.0.0)
+ hkdf (0.3.0)
+ i18n (1.12.0)
+ concurrent-ruby (~> 1.0)
+ image_processing (1.12.2)
+ mini_magick (>= 4.9.5, < 5)
+ ruby-vips (>= 2.0.17, < 3)
+ jsonapi-renderer (0.2.2)
+ jwt (2.7.0)
+ loofah (2.19.1)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ mail (2.8.1)
+ mini_mime (>= 0.1.1)
+ net-imap
+ net-pop
+ net-smtp
+ marcel (1.0.2)
+ method_source (1.0.0)
+ mini_magick (4.12.0)
+ mini_mime (1.1.2)
+ minitest (5.18.0)
+ msgpack (1.6.1)
+ multi_xml (0.6.0)
+ net-imap (0.3.4)
+ date
+ net-protocol
+ net-pop (0.1.2)
+ net-protocol
+ net-protocol (0.2.1)
+ timeout
+ net-smtp (0.3.3)
+ net-protocol
+ nio4r (2.5.8)
+ nokogiri (1.14.2-x86_64-linux)
+ racc (~> 1.4)
+ oauth2 (2.0.9)
+ faraday (>= 0.17.3, < 3.0)
+ jwt (>= 1.0, < 3.0)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 4)
+ snaky_hash (~> 2.0)
+ version_gem (~> 1.1)
+ omniauth (2.1.1)
+ hashie (>= 3.4.6)
+ rack (>= 2.2.3)
+ rack-protection
+ omniauth-google-oauth2 (1.1.1)
+ jwt (>= 2.0)
+ oauth2 (~> 2.0.6)
+ omniauth (~> 2.0)
+ omniauth-oauth2 (~> 1.8.0)
+ omniauth-oauth2 (1.8.0)
+ oauth2 (>= 1.4, < 3)
+ omniauth (~> 2.0)
+ omniauth-rails_csrf_protection (1.0.1)
+ actionpack (>= 4.2)
+ omniauth (~> 2.0)
+ openssl (3.1.0)
+ orm_adapter (0.5.0)
+ pg (1.4.6)
+ pkg-config (1.5.1)
+ public_suffix (5.0.1)
+ puma (5.6.5)
+ nio4r (~> 2.0)
+ racc (1.6.2)
+ rack (2.2.6.4)
+ rack-cors (2.0.1)
+ rack (>= 2.0.0)
+ rack-protection (3.0.5)
+ rack
+ rack-test (2.1.0)
+ rack (>= 1.3)
+ rails (6.1.7.3)
+ actioncable (= 6.1.7.3)
+ actionmailbox (= 6.1.7.3)
+ actionmailer (= 6.1.7.3)
+ actionpack (= 6.1.7.3)
+ actiontext (= 6.1.7.3)
+ actionview (= 6.1.7.3)
+ activejob (= 6.1.7.3)
+ activemodel (= 6.1.7.3)
+ activerecord (= 6.1.7.3)
+ activestorage (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ bundler (>= 1.15.0)
+ railties (= 6.1.7.3)
+ sprockets-rails (>= 2.0.0)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.5.0)
+ loofah (~> 2.19, >= 2.19.1)
+ railties (6.1.7.3)
+ actionpack (= 6.1.7.3)
+ activesupport (= 6.1.7.3)
+ method_source
+ rake (>= 12.2)
+ thor (~> 1.0)
+ rake (13.0.6)
+ ransack (4.0.0)
+ activerecord (>= 6.1.5)
+ activesupport (>= 6.1.5)
+ i18n
+ responders (3.1.0)
+ actionpack (>= 5.2)
+ railties (>= 5.2)
+ rmagick (5.2.0)
+ pkg-config (~> 1.4)
+ rspec-core (3.12.1)
+ rspec-support (~> 3.12.0)
+ rspec-expectations (3.12.2)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-mocks (3.12.4)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.12.0)
+ rspec-rails (6.0.1)
+ actionpack (>= 6.1)
+ activesupport (>= 6.1)
+ railties (>= 6.1)
+ rspec-core (~> 3.11)
+ rspec-expectations (~> 3.11)
+ rspec-mocks (~> 3.11)
+ rspec-support (~> 3.11)
+ rspec-support (3.12.0)
+ ruby-vips (2.1.4)
+ ffi (~> 1.12)
+ ruby2_keywords (0.0.5)
+ snaky_hash (2.0.1)
+ hashie
+ version_gem (~> 1.1, >= 1.1.1)
+ sprockets (4.2.0)
+ concurrent-ruby (~> 1.0)
+ rack (>= 2.2.4, < 4)
+ sprockets-rails (3.4.2)
+ actionpack (>= 5.2)
+ activesupport (>= 5.2)
+ sprockets (>= 3.0.0)
+ ssrf_filter (1.1.1)
+ thor (1.2.1)
+ timeout (0.3.2)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ useragent (0.16.10)
+ version_gem (1.1.2)
+ warden (1.2.9)
+ rack (>= 2.0.9)
+ warden-jwt_auth (0.8.0)
+ dry-auto_inject (>= 0.8, < 2)
+ dry-configurable (>= 0.13, < 2)
+ jwt (~> 2.1)
+ warden (~> 1.2)
+ webpush (1.1.0)
+ hkdf (~> 0.2)
+ jwt (~> 2.0)
+ websocket-driver (0.7.5)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.5)
+ zeitwerk (2.6.7)
+
+PLATFORMS
+ x86_64-linux
+
+DEPENDENCIES
+ active_model_serializers
+ bootsnap (>= 1.4.4)
+ byebug
+ carrierwave
+ devise
+ devise-jwt
+ dotenv-rails
+ image_processing (~> 1.2)
+ jwt
+ net-smtp
+ omniauth
+ omniauth-google-oauth2
+ omniauth-rails_csrf_protection
+ openssl
+ pg (~> 1.1)
+ puma (~> 5.0)
+ rack-cors
+ rails (~> 6.1.4, >= 6.1.4.1)
+ ransack
+ rmagick
+ rspec-rails
+ tzinfo-data
+ useragent
+ webpush
+
+RUBY VERSION
+ ruby 3.1.2p20
+
+BUNDLED WITH
+ 2.4.9
diff --git a/backend/eduapp_db/Rakefile b/backend/eduapp_db/Rakefile
index 9a5ea738..cc4cf932 100644
--- a/backend/eduapp_db/Rakefile
+++ b/backend/eduapp_db/Rakefile
@@ -1,6 +1,6 @@
-# Add your own tasks in files placed in lib/tasks ending in .rake,
-# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
-
-require_relative "config/application"
-
-Rails.application.load_tasks
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require_relative "config/application"
+
+Rails.application.load_tasks
diff --git a/backend/eduapp_db/app/channels/application_cable/channel.rb b/backend/eduapp_db/app/channels/application_cable/channel.rb
index d6726972..c915a1a7 100644
--- a/backend/eduapp_db/app/channels/application_cable/channel.rb
+++ b/backend/eduapp_db/app/channels/application_cable/channel.rb
@@ -1,4 +1,4 @@
-module ApplicationCable
- class Channel < ActionCable::Channel::Base
- end
-end
+module ApplicationCable
+ class Channel < ActionCable::Channel::Base
+ end
+end
diff --git a/backend/eduapp_db/app/channels/application_cable/connection.rb b/backend/eduapp_db/app/channels/application_cable/connection.rb
index 0ff5442f..34286ffa 100644
--- a/backend/eduapp_db/app/channels/application_cable/connection.rb
+++ b/backend/eduapp_db/app/channels/application_cable/connection.rb
@@ -1,4 +1,4 @@
-module ApplicationCable
- class Connection < ActionCable::Connection::Base
- end
-end
+module ApplicationCable
+ class Connection < ActionCable::Connection::Base
+ end
+end
diff --git a/backend/eduapp_db/app/channels/chat_channel.rb b/backend/eduapp_db/app/channels/chat_channel.rb
index 59f2058e..6926b9c3 100644
--- a/backend/eduapp_db/app/channels/chat_channel.rb
+++ b/backend/eduapp_db/app/channels/chat_channel.rb
@@ -1,74 +1,105 @@
-class ChatChannel < ApplicationCable::Channel
- require "json"
- require "edu_app_utils/encrypt_utils"
-
- def subscribed
- reject and return unless check_chat_user(params[:chat_room][1..-1], params[:connection_requester])
- @chat_name = "eduapp.channel.#{params[:chat_room]}"
- stream_from @chat_name
- end
-
- def receive(data)
- case data["command"]
- when "message"
- instance = ChatMessage.new(
- chat_base_id: params[:chat_room][1..-1],
- user_id: data["author"],
- message: data["message"],
- send_date: data["send_date"],
- )
-
- if instance.save
- newMsg = format_msg(instance)
- newMsg.merge!(JSON.parse("{\"command\": \"new_message\"}"))
-
- ActionCable.server.broadcast @chat_name, newMsg
- else
- ActionCable.server.broadcast @chat_name, { "command" => "error", "message" => "Error saving message" }
- end
-
- current_chat = ChatBase.find(params[:chat_room][1..-1])
- ChatParticipant.where(chat_base_id: current_chat.id).each do |participant|
- UserNotifsChannel.broadcast_to(
- participant.user_id,
- command: "new_msg",
- author_name: UserInfo.find_by(user_id: data["author"]).user_name,
- author_pic: UserInfo.find_by(user_id: data["author"]).profile_image,
- msg: data["message"],
- key: current_chat.private_key,
- chat_url: "#{ENV.fetch("REACT_APP_FRONTEND_ENDPOINT")}/chat/#{current_chat.isGroup ? "g" : "p"}#{current_chat.id}",
- ) if participant.user_id != data["author"]
- end
- else
- puts "DEFAULT"
- end
- end
-
- def unsubscribed
- end
-
- protected
-
- def format_msg(queryMsg)
- mainMsg = JSON.parse(queryMsg.to_json)
- mainMsg.merge!(JSON.parse("{\"chat_base\": #{queryMsg.chat_base.to_json}}"))
- mainMsg.merge!(JSON.parse("{\"user\": #{queryMsg.user.to_json}}"))
- mainMsg.delete("chat_base_id")
- mainMsg.delete("user_id")
- mainMsg["chat_base"].delete("private_key")
- mainMsg["chat_base"].delete("public_key")
-
- return mainMsg
- end
-
- # Checks if user belongs to that chat.
- def check_chat_user(chat_base_id, user_id)
- chat_participants = ChatParticipant.where(chat_base_id: chat_base_id)
- chat_participants.each do |participant|
- if participant.user_id == user_id
- return true
- end
- end
- return false
- end
-end
+class ChatChannel < ApplicationCable::Channel
+ require "json"
+ require "edu_app_utils/encrypt_utils"
+
+ def subscribed
+ reject and return unless check_chat_user(params[:chat_room][1..-1], params[:connection_requester])
+ @chat_name = "eduapp.channel.#{params[:chat_room]}"
+ stream_from @chat_name
+ end
+
+ def receive(data)
+ case data["command"]
+ when "message"
+ instance = ChatMessage.new(
+ chat_base_id: params[:chat_room][1..-1],
+ user_id: data["author"],
+ message: data["message"],
+ send_date: data["send_date"],
+ )
+
+ if instance.save
+ newMsg = format_msg(instance)
+ newMsg.merge!(JSON.parse("{\"command\": \"new_message\"}"))
+
+ ActionCable.server.broadcast @chat_name, newMsg
+ else
+ ActionCable.server.broadcast @chat_name, { "command" => "error", "message" => "Error saving message" }
+ end
+
+ current_chat = ChatBase.find(params[:chat_room][1..-1])
+ ChatParticipant.where(chat_base_id: current_chat.id).each do |participant|
+ if participant.user_id != data["author"]
+ UserNotifsChannel.broadcast_to(
+ participant.user_id,
+ command: "new_msg",
+ author_name: UserInfo.find_by(user_id: data["author"]).user_name,
+ author_pic: UserInfo.find_by(user_id: data["author"]).profile_image,
+ msg: data["message"],
+ key: current_chat.private_key,
+ chat_url: "#{ENV.fetch("REACT_APP_FRONTEND_ENDPOINT")}/chat/#{current_chat.isGroup ? "g" : "p"}#{current_chat.id}",
+ )
+
+ subcriptions = PushNotification.where(user_id: participant.user_id)
+ user = UserInfo.find_by(user_id: data["author"])
+ message = {
+ title: "Nuevo mensaje",
+ body: data["message"],
+ user: user.user_name,
+ icon: user.profile_image,
+ privKey: current_chat.private_key
+ }
+ subcriptions.each do |subcription|
+ begin
+ Webpush.payload_send(
+ endpoint: subcription.endpoint,
+ message: JSON.generate(message),
+ p256dh: subcription.p256dh,
+ auth: subcription.auth,
+ vapid: {
+ subject: "mailto:email@example.com",
+ public_key: ENV.fetch('VAPID_PUBLIC_KEY'),
+ private_key: ENV.fetch('VAPID_PRIVATE_KEY')
+ }
+ )
+ rescue Webpush::ExpiredSubscription => e
+ subcription.destroy
+ rescue Exception => e
+ e
+ end
+ end
+ end
+ end
+ else
+ puts "DEFAULT"
+ end
+ end
+
+ def unsubscribed
+ end
+
+ protected
+
+ def format_msg(queryMsg)
+ mainMsg = JSON.parse(queryMsg.to_json)
+ mainMsg.merge!(JSON.parse("{\"chat_base\": #{queryMsg.chat_base.to_json}}"))
+ mainMsg.merge!(JSON.parse("{\"user\": #{queryMsg.user.to_json}}"))
+ mainMsg.delete("chat_base_id")
+ mainMsg.delete("user_id")
+ mainMsg["chat_base"].delete("private_key")
+ mainMsg["chat_base"].delete("public_key")
+
+ return mainMsg
+ end
+
+ # Checks if user belongs to that chat.
+ def check_chat_user(chat_base_id, user_id)
+ chat_participants = ChatParticipant.where(chat_base_id: chat_base_id)
+ chat_participants.each do |participant|
+ if participant.user_id == user_id
+ return true
+ end
+ end
+ return false
+ end
+end
diff --git a/backend/eduapp_db/app/channels/user_notifs_channel.rb b/backend/eduapp_db/app/channels/user_notifs_channel.rb
index 8ca1e99c..94a953b1 100644
--- a/backend/eduapp_db/app/channels/user_notifs_channel.rb
+++ b/backend/eduapp_db/app/channels/user_notifs_channel.rb
@@ -1,67 +1,67 @@
-class UserNotifsChannel < ApplicationCable::Channel
- def subscribed
- @user_count = 0 unless @user_count.instance_of?(Integer)
- reject unless check_auth_token(params[:token]) && check_user && @user_count == 0
- @chat_name = "eduapp.notifs.user.#{params[:user_id]}"
- @user_count = 1
- stream_from @chat_name
- stream_for @notifs_user
- end
-
- def receive(cmd)
- case cmd["command"]
- when "new_msgs"
- puts "hi"
- else
- end
- end
-
- def unsubscribed
- @user_count = 0
- @notifs_user = nil
- end
-
- private
-
- def check_auth_token(token)
- if token.nil?
- return false
- end
-
- token = token.split("Bearer ").last
- jwt_payload = User.unlock_token(token)
- if jwt_payload.instance_of? Array
- if Time.now.to_i > Integer(jwt_payload[0]["exp"])
- return false
- end
- jtiMatch = JtiMatchList.where(user_id: jwt_payload[0]["sub"], jti: jwt_payload[0]["jti"])
- if !jtiMatch.present?
- return false
- end
- @notifs_user = jwt_payload[0]["sub"]
- else
- return false
- end
- end
-
- # If token check succeeds, checks if there is already a user in the websocket.
- def check_user
- if @notifs_user.nil?
- return false
- else
- user = User.find(@notifs_user)
- if user.nil?
- return false
- end
-
- if user.id != params[:user_id]
- return false
- end
- return true
- end
- end
-
- def set_user_count
- @user_count = 0
- end
-end
+class UserNotifsChannel < ApplicationCable::Channel
+ def subscribed
+ @user_count = 0 unless @user_count.instance_of?(Integer)
+ reject unless check_auth_token(params[:token]) && check_user && @user_count == 0
+ @chat_name = "eduapp.notifs.user.#{params[:user_id]}"
+ @user_count = 1
+ stream_from @chat_name
+ stream_for @notifs_user
+ end
+
+ def receive(cmd)
+ case cmd["command"]
+ when "new_msgs"
+ puts "hi"
+ else
+ end
+ end
+
+ def unsubscribed
+ @user_count = 0
+ @notifs_user = nil
+ end
+
+ private
+
+ def check_auth_token(token)
+ if token.nil?
+ return false
+ end
+
+ token = token.split("Bearer ").last
+ jwt_payload = User.unlock_token(token)
+ if jwt_payload.instance_of? Array
+ if Time.now.to_i > Integer(jwt_payload[0]["exp"])
+ return false
+ end
+ jtiMatch = JtiMatchList.where(user_id: jwt_payload[0]["sub"], jti: jwt_payload[0]["jti"])
+ if !jtiMatch.present?
+ return false
+ end
+ @notifs_user = jwt_payload[0]["sub"]
+ else
+ return false
+ end
+ end
+
+ # If token check succeeds, checks if there is already a user in the websocket.
+ def check_user
+ if @notifs_user.nil?
+ return false
+ else
+ user = User.find(@notifs_user)
+ if user.nil?
+ return false
+ end
+
+ if user.id != params[:user_id]
+ return false
+ end
+ return true
+ end
+ end
+
+ def set_user_count
+ @user_count = 0
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/application_controller.rb b/backend/eduapp_db/app/controllers/application_controller.rb
index 50d0a443..768d0de5 100644
--- a/backend/eduapp_db/app/controllers/application_controller.rb
+++ b/backend/eduapp_db/app/controllers/application_controller.rb
@@ -1,314 +1,332 @@
-class ApplicationController < ActionController::API
- before_action :configure_permitted_parameters, if: :devise_controller?
-
- protected
-
- def configure_permitted_parameters
- added_attrs = [:username, :email, :password, :password_confirmation]
- devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
- devise_parameter_sanitizer.permit(:sign_in) do |user_params|
- user_params.permit(:username, :email)
- end
- end
-
- # Returns the ID's information from the requested table.
- def return_table(table)
- case table
- when "users"
- return User.find(params[:id])
- when "courses"
- return Course.find(params[:id])
- when "sessions"
- return EduappUserSession.find(params[:id])
- when "institutions"
- return Institution.find(params[:id])
- when "resources"
- return Resource.find(params[:id])
- when "subjects"
- return Subject.find(params[:id])
- end
- end
-
- # Renders the desired table's ```extra_fields```.
- def get_extrafields
- authenticate_user!
- table = return_table(params[:table])
- render json: table.extra_fields and return
- end
-
- # Creates new ```extra_fields``` for the requested table.
- def push_extrafields
- authenticate_user!
- table = return_table(params[:table])
- body = request.body.read.to_s
-
- extrafields_body = table.extra_fields
- extrafields_body.push(body)
-
- if table.update(extra_fields: extrafields_body)
- table.save
- render json: table.extra_fields and return
- else
- render json: { error: "Error updating extra fields" }, status: 422 and return
- end
- end
-
- # Updates the desired ```extra_fields``` from the given table.
- def update_extrafield
- authenticate_user!
- table = return_table(params[:table])
- body = JSON.parse(request.body.read)
- extrafields = table.extra_fields
-
- extrafields_updated = []
- extrafields.each do |extrafield|
- extrafield = JSON.parse(extrafield)
- if extrafield["name"] === body["name"]
- extrafield["value"] = body["value"]
- end
- extrafields_updated.push(JSON.generate(extrafield))
- end
-
- if table.update(extra_fields: extrafields_updated)
- render json: table.extra_fields and return
- else
- render json: { error: "Error updating extra fields" }, status: 422 and return
- end
- end
-
- # Deletes any ```extra_fields``` from the given table.
- def delete_extrafield
- authenticate_user!
- table = return_table(params[:table])
- name = params[:field] || params[:name]
-
- extrafields_updated = []
- extrafields = table.extra_fields
- extrafields.each do |extrafield|
- extrafield = JSON.parse(extrafield)
- if extrafield["name"] != name
- extrafields_updated.push(JSON.generate(extrafield))
- end
- end
-
- if table.update(extra_fields: extrafields_updated)
- render json: table.extra_fields and return true
- else
- render json: { error: "Error deleting extra fields" }, status: 422 and return
- end
- end
-
- # Filters the desired table's ```extra_fields``` for further filtration.
- def filter_extrafields(extras, table)
- check_extra_fields(table)
- extras = JSON.parse(Base64.decode64(extras))
- valuable = table.where.not(extra_fields: [])
-
- return nil if extras.nil?
-
- ids = []
- valuable.each do |entry|
- next if ids.include? entry.id
- entry.extra_fields.each do |field|
- break if ids.include? entry.id
- extras.each do |extra_field|
- break if ids.include? entry.id
- extra_field = { extra_field[0] => extra_field[1] }
- field = JSON.parse field
-
- ids.push(entry.id) if field["value"] =~ /^#{extra_field[field["name"]]}.*$/ && !extra_field[field["name"]].nil?
- end
- end
- end
-
- return ids.length > 0 ? table.where(id: ids) : nil
- end
-
- private
-
- # AUTH
-
- # Raises an exception if the table is not elegible for extra fields.
- def check_extra_fields(table)
- raise Exception.new "Table does is not elegible for extra fields." unless table.column_names.include?("extra_fields")
- end
-
- # Checks a JWT token from the request and returns an appropiate response.
- def authenticate_user!(options = {})
- if request.headers["eduauth"].present?
- token = request.headers["eduauth"].split("Bearer ").last
- jwt_payload = User.unlock_token(token)
- if jwt_payload.instance_of? Array
- if Time.now.to_i > Integer(jwt_payload[0]["exp"])
- render json: { error: "Token has expired." }, status: 428 and return
- end
- jtiMatch = JtiMatchList.where(user_id: jwt_payload[0]["sub"], jti: jwt_payload[0]["jti"])
- if jtiMatch.count === 0
- render json: { error: "Token Mismatch." }, status: 406 and return
- end
- @current_user = jwt_payload[0]["sub"]
- else
- render json: { error: "Invalid token." }, status: :forbidden and return
- end
- else
- render json: { error: "No auth provided." }, status: :unauthorized and return
- end
- end
-
- # Checks the incoming role of a user provided by its JWT Token.
- def check_role!
- if request.headers["eduauth"].present?
- token = request.headers["eduauth"].split("Bearer ").last
- jwt_payload = User.unlock_token(token)
- if jwt_payload.instance_of? Array
- valid_role = false
- UserRole.all.each do |role|
- if role.name === jwt_payload[0]["aud"]
- valid_role = true
- break
- end
- end
-
- if !valid_role
- render json: { error: "Invalid role." }, status: :forbidden and return
- end
- end
- end
- end
-
- def current_user
- @current_user ||= super || User.where(id: @current_user)
- end
-
- def signed_in?
- @current_user.present?
- end
-
- # UTILS
-
- # Returns a ```UserRole``` entry for the currently existing admin role.
- def get_admin_role
- return UserRole.where(name: "eduapp-admin").first
- end
-
- # Returns the user's respective ```UserRole``` information.
- def get_user_roles(user_id = @current_user)
- return UserRole.find(UserInfo.where(user_id: user_id).first.user_role_id)
- end
-
- # Serializes each element in an array.
- def serialize_each(array, iExcept = [], iInclude = [])
- s = []
- array.each do |item|
- s.push(item.serializable_hash(except: iExcept, include: iInclude))
- end
- return s
- end
-
- # Paginates an ```ActiveRecord``` query.
- def query_paginate(query, page, limit = 10)
- page = Integer(page)
- if page - 1 < 0
- return { :error => "Page cannot be less than 1" }
- end
- return { :current_page => query.limit(limit).offset((page - 1) * limit), :total_pages => (query.count.to_f / limit).ceil, :page => page }
- end
-
- # Paginates an array.
- def array_paginate(array, page, limit = 10)
- return array.slice(Integer(page) > 0 ? Integer(page) - 1 : 0, limit)
- end
-
- # A parser made to correctly return a decoded order filter.
- def parse_filter_order(order)
- order = JSON.parse(Base64.decode64(order))
- return { order["field"] => order["order"] == "asc" ? :asc : :desc }
- end
-
- # PERMISSIONS
-
- # Deny access due to permissions.
- def deny_perms_access!
- render json: { error: "You do not have permission to access this endpoint." }, status: :forbidden and return false
- end
-
- # Deny action due to permissions.
- def deny_perms_action!
- render json: { error: "You do not have permission to perform this action." }, status: 405 and return false
- end
-
- # Checks the owner that executed the desired action.
- def check_action_owner!(requested_id)
- if requested_id === @current_user
- return true
- else
- return deny_perms_action! unless get_user_roles.name === get_admin_role.name and return true
- end
- end
-
- # Checks ```UserRole``` permissions for querying everything.
- def check_perms_all!(user_roles)
- if user_roles[0]
- return true
- else
- return deny_perms_access!
- end
- end
-
- # Checks ```UserRole``` permissions for performing specific queries.
- def check_perms_query!(user_roles)
- if user_roles[1]
- return true
- else
- return deny_perms_access!
- end
- end
-
- # Checks ```UserRole``` permissions for querying information about itself..
- def check_perms_query_self!(user_roles, query_user_id)
- if user_roles[2]
- if query_user_id == @current_user
- return true
- else
- return check_perms_query!(user_roles)
- end
- else
- return deny_perms_access!
- end
- end
-
- # Checks ```UserRole``` permissions for creating.
- def check_perms_write!(user_roles)
- if user_roles[3]
- return true
- else
- return deny_perms_action!
- end
- end
-
- # Checks ```UserRole``` permissions for updating.
- def check_perms_update!(user_roles, needs_owner_check, requested_id)
- if user_roles[4]
- return true
- else
- if needs_owner_check
- return check_action_owner!(requested_id)
- else
- return deny_perms_action!
- end
- end
- end
-
- # Checks ```UserRole``` permissions for deleting.
- def check_perms_delete!(user_roles, needs_owner_check, requested_id)
- if user_roles[5]
- return true
- else
- if needs_owner_check
- return check_action_owner!(requested_id)
- else
- return deny_perms_action!
- end
- end
- end
-end
+class ApplicationController < ActionController::API
+ before_action :configure_permitted_parameters, if: :devise_controller?
+
+
+ # Renders the desired table's ```extra_fields```.
+ def get_extrafields
+ authenticate_user!
+ table = return_table(params[:table])
+ render json: table.extra_fields and return
+ end
+
+ # Creates new ```extra_fields``` for the requested table.
+ def push_extrafields
+ authenticate_user!
+ table = return_table(params[:table])
+ body = request.body.read.to_s
+
+ extrafields_body = table.extra_fields
+ extrafields_body.push(body)
+
+ if table.update(extra_fields: extrafields_body)
+ table.save
+ render json: table.extra_fields and return
+ else
+ render json: { error: "Error updating extra fields" }, status: 422 and return
+ end
+ end
+
+ # Updates the desired ```extra_fields``` from the given table.
+ def update_extrafield
+ authenticate_user!
+ table = return_table(params[:table])
+ body = JSON.parse(request.body.read)
+ extrafields = table.extra_fields
+
+ extrafields_updated = []
+ extrafields.each do |extrafield|
+ extrafield = JSON.parse(extrafield)
+ if extrafield["name"] === body["name"]
+ extrafield["value"] = body["value"]
+ end
+ extrafields_updated.push(JSON.generate(extrafield))
+ end
+
+ if table.update(extra_fields: extrafields_updated)
+ render json: table.extra_fields and return
+ else
+ render json: { error: "Error updating extra fields" }, status: 422 and return
+ end
+ end
+
+ # Deletes any ```extra_fields``` from the given table.
+ def delete_extrafield
+ authenticate_user!
+ table = return_table(params[:table])
+ name = params[:field] || params[:name]
+
+ extrafields_updated = []
+ extrafields = table.extra_fields
+ extrafields.each do |extrafield|
+ extrafield = JSON.parse(extrafield)
+ if extrafield["name"] != name
+ extrafields_updated.push(JSON.generate(extrafield))
+ end
+ end
+
+ if table.update(extra_fields: extrafields_updated)
+ render json: table.extra_fields and return true
+ else
+ render json: { error: "Error deleting extra fields" }, status: 422 and return
+ end
+ end
+
+
+ protected
+
+ def configure_permitted_parameters
+ added_attrs = [:username, :email, :password, :password_confirmation]
+ devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
+ devise_parameter_sanitizer.permit(:sign_in) do |user_params|
+ user_params.permit(:username, :email)
+ end
+ end
+
+ # Returns the ID's information from the requested table.
+ def return_table(table)
+ case table
+ when "users"
+ return User.find(params[:id])
+ when "courses"
+ return Course.find(params[:id])
+ when "sessions"
+ return EduappUserSession.find(params[:id])
+ when "institutions"
+ return Institution.find(params[:id])
+ when "resources"
+ return Resource.find(params[:id])
+ when "subjects"
+ return Subject.find(params[:id])
+ end
+ end
+
+
+ # Filters the desired table's ```extra_fields``` for further filtration.
+ def filter_extrafields(extras, table)
+ check_extra_fields(table)
+ extras = JSON.parse(Base64.decode64(extras))
+ valuable = table.where.not(extra_fields: [])
+
+ return nil if extras.nil?
+
+ ids = []
+ valuable.each do |entry|
+ next if ids.include? entry.id
+ entry.extra_fields.each do |field|
+ break if ids.include? entry.id
+ extras.each do |extra_field|
+ break if ids.include? entry.id
+ extra_field = { extra_field[0] => extra_field[1] }
+ field = field.instance_of?(String) ? JSON.parse(field) : field
+
+ ids.push(entry.id) if field["value"] =~ /^#{extra_field[field["name"]]}.*$/ && !extra_field[field["name"]].nil?
+ end
+ end
+ end
+
+ return ids.length > 0 ? table.where(id: ids) : nil
+ end
+
+ # PERMISSIONS
+
+ # Deny access due to permissions.
+ def deny_perms_access!
+ render json: { error: "You do not have permission to access this endpoint." }, status: :forbidden and return false
+ end
+
+ # Deny action due to permissions.
+ def deny_perms_action!
+ render json: { error: "You do not have permission to perform this action." }, status: 405 and return false
+ end
+
+
+ private
+
+ # AUTH
+
+ # Raises an exception if the table is not elegible for extra fields.
+ def check_extra_fields(table)
+ raise Exception.new "Table does is not elegible for extra fields." unless table.column_names.include?("extra_fields")
+ end
+
+ # Checks a JWT token from the request and returns an appropiate response.
+ def authenticate_user!(options = {})
+ if request.headers["eduauth"].present?
+ token = request.headers["eduauth"].split("Bearer ").last
+ jwt_payload = User.unlock_token(token)
+ if jwt_payload.instance_of? Array
+ if Time.now.to_i > Integer(jwt_payload[0]["exp"])
+ render json: { error: "Token has expired." }, status: 428 and return
+ end
+ jtiMatch = JtiMatchList.where(user_id: jwt_payload[0]["sub"], jti: jwt_payload[0]["jti"])
+ if jtiMatch.count === 0
+ render json: { error: "Token Mismatch." }, status: 406 and return
+ end
+ @current_user = jwt_payload[0]["sub"]
+ else
+ render json: { error: "Invalid token." }, status: :forbidden and return
+ end
+ else
+ render json: { error: "No auth provided." }, status: :unauthorized and return
+ end
+ end
+
+ # Checks the incoming role of a user provided by its JWT Token.
+ def check_role!
+ if request.headers["eduauth"].present?
+ token = request.headers["eduauth"].split("Bearer ").last
+ jwt_payload = User.unlock_token(token)
+ if jwt_payload.instance_of? Array
+ valid_role = false
+ UserRole.all.each do |role|
+ if role.name === jwt_payload[0]["aud"]
+ valid_role = true
+ break
+ end
+ end
+
+ if !valid_role
+ render json: { error: "Invalid role." }, status: :forbidden and return
+ end
+ end
+ end
+ end
+
+ def current_user
+ @current_user ||= super || User.where(id: @current_user)
+ end
+
+ def signed_in?
+ @current_user.present?
+ end
+
+ # UTILS
+
+ # Returns a ```UserRole``` entry for the currently existing admin role.
+ def get_admin_role
+ return UserRole.where(name: "eduapp-admin").first
+ end
+
+ # Returns the user's respective ```UserRole``` information.
+ def get_user_roles(user_id = @current_user)
+ return UserRole.find(UserInfo.where(user_id: user_id).first.user_role_id)
+ end
+
+ # Serializes each element in an array.
+ def serialize_each(array, iExcept = [], iInclude = [])
+ s = []
+ array.each do |item|
+ s.push(item.serializable_hash(except: iExcept, include: iInclude))
+ end
+ return s
+ end
+
+ # Paginates an ```ActiveRecord``` query.
+ def query_paginate(query, page, limit = 10)
+ page = begin Integer(page) rescue 1 end
+ if page - 1 < 0
+ return { :error => "Page cannot be less than 1" }
+ end
+ return { :current_page => query.limit(limit).offset((page - 1) * limit), :total_pages => (query.count.to_f / limit).ceil, :page => page }
+ end
+
+ # Paginates an array.
+ def array_paginate(array, page, limit = 10)
+ return array.slice(Integer(page) > 0 ? Integer(page) - 1 : 0, limit)
+ end
+
+ # A parser made to correctly return a decoded order filter.
+ def parse_filter_order(order, relational_order = {'.' => ''})
+ order = order.is_a?(String) ? JSON.parse(Base64.decode64(order)) : order
+ field = relational_order[order["field"]] || order["field"] || nil
+
+ return { field => order['order'] == "asc" ? :asc : :desc, id: :asc }
+ end
+
+ # PERMISSIONS
+
+ # Deny access due to permissions.
+ def deny_perms_access!
+ render json: { error: "You do not have permission to access this endpoint." }, status: :forbidden and return false
+ end
+
+ # Deny action due to permissions.
+ def deny_perms_action!
+ render json: { error: "You do not have permission to perform this action." }, status: 405 and return false
+ end
+
+ # Checks the owner that executed the desired action.
+ def check_action_owner!(requested_id, render_error = true)
+ if requested_id === @current_user
+ return true
+ else
+ return render_error ? (deny_perms_action! unless get_user_roles.name === get_admin_role.name) : false
+ end
+ end
+
+ # Checks ```UserRole``` permissions for querying everything.
+ def check_perms_all!(user_roles)
+ if user_roles[0]
+ return true
+ else
+ return deny_perms_access!
+ end
+ end
+
+ # Checks ```UserRole``` permissions for performing specific queries.
+ def check_perms_query!(user_roles, render_error= true)
+ if user_roles[1]
+ return true
+ else
+ return render_error ? deny_perms_access! : false
+ end
+ end
+
+ # Checks ```UserRole``` permissions for querying information about itself..
+ def check_perms_query_self!(user_roles, query_user_id)
+ if user_roles[2]
+ if query_user_id == @current_user
+ return true
+ else
+ return check_perms_query!(user_roles)
+ end
+ else
+ return deny_perms_access!
+ end
+ end
+
+ # Checks ```UserRole``` permissions for creating.
+ def check_perms_write!(user_roles)
+ if user_roles[3]
+ return true
+ else
+ return deny_perms_action!
+ end
+ end
+
+ # Checks ```UserRole``` permissions for updating.
+ def check_perms_update!(user_roles, needs_owner_check = false, requested_id = nil, render_error = true)
+ if user_roles[4]
+ return true
+ else
+ if needs_owner_check
+ return check_action_owner!(requested_id, render_error)
+ else
+ return render_error ? deny_perms_action! : false
+ end
+ end
+ end
+
+ # Checks ```UserRole``` permissions for deleting.
+ def check_perms_delete!(user_roles, needs_owner_check, requested_id)
+ if user_roles[5]
+ return true
+ else
+ if needs_owner_check
+ return check_action_owner!(requested_id)
+ else
+ return deny_perms_action!
+ end
+ end
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/calendar_annotations_controller.rb b/backend/eduapp_db/app/controllers/calendar_annotations_controller.rb
index d564f54b..8679bab2 100644
--- a/backend/eduapp_db/app/controllers/calendar_annotations_controller.rb
+++ b/backend/eduapp_db/app/controllers/calendar_annotations_controller.rb
@@ -1,218 +1,219 @@
-class CalendarAnnotationsController < ApplicationController
- before_action :set_calendar_annotation, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /calendar_annotations
- def index
- wants_event_for_calendar = false
-
- # Returns events in a way for it to be readable by the App's calendar.
- if params[:user_id]
- wants_event_for_calendar = true
- if !check_perms_query_self!(get_user_roles.perms_events, params[:user_id])
- return
- end
- # TODO: Possible refactorization:
- # tuitions = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
- # @subjects = Subject.where(course_id: tuitions)
- # @sessions = CalendarAnnotation.where(subject_id: @subjects)
- # @calendarEvents = @sessions.where(isGlobal: false)
- # @colorEvents = @subjects.pluck(:id, :color)
-
- @TuitionsUserId = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
- @calendar_isGlobal = CalendarAnnotation.where(isGlobal: true)
- @subjects = []
- @calendarEvents = []
- @sessions = []
- for course in @TuitionsUserId
- @subjects += Subject.where(course_id: course).pluck(:id)
- end
-
- for subject in @subjects
- @calendarEvents += CalendarAnnotation.where(isGlobal: false, subject_id: subject)
- @colorEvents = Subject.where(course_id: @TuitionsUserId).pluck(:id, :color)
- end
-
- for subject in @subjects
- @sessions += CalendarAnnotation.where(subject_id: subject)
- end
- @calendar_annotations = { :globalEvents => @calendar_isGlobal, :calendarEvents => @calendarEvents, :sessions => @sessions, :colorEvents => @colorEvents }
- else
- if !check_perms_all!(get_user_roles.perms_events)
- return
- end
- @calendar_annotations = CalendarAnnotation.all
- end
-
- if !wants_event_for_calendar
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @calendar_annotations = @calendar_annotations.order(parse_filter_order(params[:order]))
- else
- @calendar_annotations = @calendar_annotations.order(annotation_title: :asc)
- end
- end
-
- if !wants_event_for_calendar
- if params[:page]
- @calendar_annotations = query_paginate(@calendar_annotations, params[:page])
- @calendar_annotations[:current_page] = serialize_each(@calendar_annotations[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:subject, :user])
- end
- end
-
- render json: @calendar_annotations
- end
-
- def calendar_info
- if !check_perms_query_self!(get_user_roles.perms_events, params[:user_id])
- return
- end
- annotation = CalendarAnnotation.where(isGlobal: true, isPop: true).order(:created_at).pluck(:annotation_start_date, :annotation_end_date)
- now = Time.now.to_i
- event = []
- for date in annotation
- stime = date[0].to_time.to_i
- etime = date[1].to_time.to_i
- if stime > now or now < etime
- event += CalendarAnnotation.where(annotation_start_date: date[0], annotation_end_date: date[1])
- end
- end
- render json: event
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- events_query = {}
- subject_query = {}
- params.each do |param|
- next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "calendar_annotations"
- next unless param[1] != "null" && param[1].length > 0
-
- query = { param[0] => param[1] }
- case param[0]
- when "id", "annotation_title", "annotation_description", "event_author"
- events_query.merge!(query)
- when "subject_name"
- subject_query.merge!(query)
- end
- end
-
- final_query = nil
-
- if !events_query.empty?
- query = nil
-
- if events_query["id"]
- ids = []
- CalendarAnnotation.all.each do |e|
- ids << e.id if e.id.to_s =~ /^#{events_query["id"]}.*$/
- end
- query = CalendarAnnotation.where(id: ids)
- end
-
- if events_query["annotation_title"]
- if !query.nil?
- query = query.where("annotation_title LIKE ?", "%#{events_query["annotation_title"]}%")
- else
- query = CalendarAnnotation.where("annotation_title LIKE ?", "%#{events_query["annotation_title"]}%")
- end
- end
-
- if events_query["annotation_description"]
- if !query.nil?
- query = query.where("annotation_description LIKE ?", "%#{events_query["annotation_description"]}%")
- else
- query = CalendarAnnotation.where("annotation_description LIKE ?", "%#{events_query["annotation_description"]}%")
- end
- end
-
- if events_query["event_author"]
- if !query.nil?
- query = query.where(user_id: User.where("email LIKE ?", "%#{events_query["event_author"]}%"))
- else
- query = CalendarAnnotation.where(user_id: User.where("email LIKE ?", "%#{events_query["event_author"]}%"))
- end
- end
-
- final_query = query
- end
-
- if !final_query.nil? && !subject_query.empty?
- final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- elsif !subject_query.empty?
- final_query = CalendarAnnotation.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /calendar_annotations/1
- def show
- if !check_perms_query!(get_user_roles.perms_events)
- return
- end
- render json: @calendar_annotation
- end
-
- def show_calendar_event
- if !check_perms_query!(get_user_roles.perms_events)
- return
- end
- calendar_annotation = CalendarAnnotation.where(isPop: true).last
- render json: calendar_annotation
- end
-
- # POST /calendar_annotations
- def create
- if !check_perms_write!(get_user_roles.perms_events)
- return
- end
- @calendar_annotation = CalendarAnnotation.new(calendar_annotation_params)
-
- if @calendar_annotation.save
- render json: @calendar_annotation, status: :created, location: @calendar_annotation
- else
- render json: @calendar_annotation.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /calendar_annotations/1
- def update
- if !check_perms_update!(get_user_roles.perms_events, false, :null)
- return
- end
- puts "A: #{calendar_annotation_params}"
- if @calendar_annotation.update(calendar_annotation_params)
- render json: @calendar_annotation
- else
- render json: @calendar_annotation.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /calendar_annotations/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_events, false, :null)
- return
- end
- @calendar_annotation.destroy
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_calendar_annotation
- @calendar_annotation = CalendarAnnotation.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def calendar_annotation_params
- params.require(:calendar_annotation).permit(:annotation_start_date, :annotation_end_date, :annotation_title, :annotation_description, :isGlobal, :isPop, :user_id, :subject_id)
- end
-end
+class CalendarAnnotationsController < ApplicationController
+ before_action :set_calendar_annotation, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /calendar_annotations
+ def index
+ wants_event_for_calendar = false
+
+ # Returns events in a way for it to be readable by the App's calendar.
+ if params[:user_id]
+ wants_event_for_calendar = true
+ if !check_perms_query_self!(get_user_roles.perms_events, params[:user_id])
+ return
+ end
+ # TODO: Possible refactorization:
+ # tuitions = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
+ # @subjects = Subject.where(course_id: tuitions)
+ # @sessions = CalendarAnnotation.where(subject_id: @subjects)
+ # @calendarEvents = @sessions.where(isGlobal: false)
+ # @colorEvents = @subjects.pluck(:id, :color)
+
+ # @TuitionsUserId = SubjectsUser.where(user_id: params[:user_id]).pluck(:subject_id)
+ @calendar_isGlobal = CalendarAnnotation.where(isGlobal: true)
+ @calendarEvents = []
+ @sessions = []
+ @colorEvents = []
+ user = User.find(params[:user_id])
+ if user.user_info.user_role.name == 'eduapp-teacher'
+ @subjects = user.user_info.teaching_list
+ else
+ @subjects = user.subjects.pluck(:id)
+ end
+ for subject in @subjects
+ subj = Subject.find(subject)
+ @calendarEvents += CalendarAnnotation.where(isGlobal: false, subject_id: subject)
+ @colorEvents << [ subj.id, subj.color]
+ @sessions += EduappUserSession.where(subject_id: subject)
+ end
+ @calendar_annotations = { :globalEvents => @calendar_isGlobal, :calendarEvents => @calendarEvents, :sessions => @sessions, :colorEvents => @colorEvents }
+ else
+ if !check_perms_all!(get_user_roles.perms_events)
+ return
+ end
+ @calendar_annotations = CalendarAnnotation.all
+ end
+
+ if !wants_event_for_calendar
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ @calendar_annotations = @calendar_annotations.order(parse_filter_order(params[:order]))
+ else
+ @calendar_annotations = @calendar_annotations.order(annotation_title: :asc)
+ end
+ end
+
+ if !wants_event_for_calendar
+ if params[:page]
+ @calendar_annotations = query_paginate(@calendar_annotations, params[:page])
+ @calendar_annotations[:current_page] = serialize_each(@calendar_annotations[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:subject, :user])
+ end
+ end
+
+ render json: @calendar_annotations
+ end
+
+ # TODO: revisar
+ def calendar_info
+ if !check_perms_query_self!(get_user_roles.perms_events, params[:user_id])
+ return
+ end
+ annotation = CalendarAnnotation.where(isGlobal: true, isPop: true).order(:created_at).pluck(:annotation_start_date, :annotation_end_date)
+ now = Time.now.to_i
+ event = []
+ for date in annotation
+ stime = date[0].to_time.to_i
+ etime = date[1].to_time.to_i
+ if stime > now or now < etime
+ event += CalendarAnnotation.where(annotation_start_date: date[0], annotation_end_date: date[1])
+ end
+ end
+ render json: event
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ events_query = {}
+ subject_query = {}
+ params.each do |param|
+ next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "calendar_annotations"
+ next unless param[1] != "null" && param[1].length > 0
+
+ query = { param[0] => param[1] }
+ case param[0]
+ when "id", "annotation_title", "annotation_description", "event_author"
+ events_query.merge!(query)
+ when "subject_name"
+ subject_query.merge!(query)
+ end
+ end
+
+ final_query = nil
+
+ if !events_query.empty?
+ query = nil
+
+ if events_query["id"]
+ ids = []
+ CalendarAnnotation.all.each do |e|
+ ids << e.id if e.id.to_s =~ /^#{events_query["id"]}.*$/
+ end
+ query = CalendarAnnotation.where(id: ids)
+ end
+
+ if events_query["annotation_title"]
+ if !query.nil?
+ query = query.where("annotation_title LIKE ?", "%#{events_query["annotation_title"]}%")
+ else
+ query = CalendarAnnotation.where("annotation_title LIKE ?", "%#{events_query["annotation_title"]}%")
+ end
+ end
+
+ if events_query["annotation_description"]
+ if !query.nil?
+ query = query.where("annotation_description LIKE ?", "%#{events_query["annotation_description"]}%")
+ else
+ query = CalendarAnnotation.where("annotation_description LIKE ?", "%#{events_query["annotation_description"]}%")
+ end
+ end
+
+ if events_query["event_author"]
+ if !query.nil?
+ query = query.where(user_id: User.where("email LIKE ?", "%#{events_query["event_author"]}%"))
+ else
+ query = CalendarAnnotation.where(user_id: User.where("email LIKE ?", "%#{events_query["event_author"]}%"))
+ end
+ end
+
+ final_query = query
+ end
+
+ if !final_query.nil? && !subject_query.empty?
+ final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ elsif !subject_query.empty?
+ final_query = CalendarAnnotation.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /calendar_annotations/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_events)
+ return
+ end
+ render json: @calendar_annotation
+ end
+
+ def show_calendar_event
+ if !check_perms_query!(get_user_roles.perms_events)
+ return
+ end
+ calendar_annotation = CalendarAnnotation.where(isPop: true).last
+ render json: calendar_annotation
+ end
+
+ # POST /calendar_annotations
+ def create
+ if !check_perms_write!(get_user_roles.perms_events)
+ return
+ end
+ @calendar_annotation = CalendarAnnotation.new(calendar_annotation_params)
+
+ if @calendar_annotation.save
+ render json: @calendar_annotation, status: :created, location: @calendar_annotation
+ else
+ render json: @calendar_annotation.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /calendar_annotations/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_events, false, :null)
+ return
+ end
+ puts "A: #{calendar_annotation_params}"
+ if @calendar_annotation.update(calendar_annotation_params)
+ render json: @calendar_annotation
+ else
+ render json: @calendar_annotation.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /calendar_annotations/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_events, false, :null)
+ return
+ end
+ @calendar_annotation.destroy
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_calendar_annotation
+ @calendar_annotation = CalendarAnnotation.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def calendar_annotation_params
+ params.require(:calendar_annotation).permit(:annotation_start_date, :annotation_end_date, :annotation_title, :annotation_description, :isGlobal, :isPop, :user_id, :subject_id)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/chat_bases_controller.rb b/backend/eduapp_db/app/controllers/chat_bases_controller.rb
index 3f86b95e..9a58a70d 100644
--- a/backend/eduapp_db/app/controllers/chat_bases_controller.rb
+++ b/backend/eduapp_db/app/controllers/chat_bases_controller.rb
@@ -1,202 +1,220 @@
-class ChatBasesController < ApplicationController
- before_action :set_chat_basis, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- require "edu_app_utils/encrypt_utils"
-
- # GET /chat_bases
- def index
- wants_complete_chat = false
-
- # Made to return all necessary information for a chat.
- if params[:complete_chat_for]
- wants_complete_chat = true
- if !check_user_in_chat(params[:complete_chat_for])
- return
- end
- chat = ChatBase.find(params[:complete_chat_for]).serializable_hash(:except => [:created_at, :updated_at])
- other_participants = ChatParticipant.where(chat_base_id: params[:complete_chat_for])
-
- participants = []
- other_participants.each do |participant|
- p = UserInfo.where(user_id: participant.user_id).first.serializable_hash(:only => [:profile_image, :user_name], :include => [:user])
- p.merge!({ isChatAdmin: participant.isChatAdmin })
- participants.push(p)
- end
-
- # Be able to gather the counterpart info even if they left the chat
- if chat["chat_name"].include?("private_chat_")
- if participants.length < 2
- name_disect = chat["chat_name"].split("_")
- name_disect.delete("private")
- name_disect.delete("chat")
-
- chat_counterpart_id = name_disect[0] == participants[0]["user"]["id"] ? name_disect[1] : name_disect[0]
- chat_counterpart = UserInfo.where(user_id: chat_counterpart_id).first.serializable_hash(:only => [:profile_image, :user_name], :include => [:user])
- participants.push(chat_counterpart)
- end
- end
-
- @chat_bases = { chat: chat, participants: participants }
- else
- if !check_perms_all!(get_user_roles.perms_chat)
- return
- end
- @chat_bases = ChatBase.all
- end
-
- if !wants_complete_chat
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- order = JSON.parse(Base64.decode64(params[:order]))
- order["field"] = order["field"] == "name" ? "chat_name" : order["field"]
- @chat_bases = @chat_bases.order({ order["field"] => order["order"] == "asc" ? :asc : :desc })
- else
- @chat_bases = @chat_bases.order(chat_name: :asc)
- end
- end
-
- if params[:page]
- @chat_bases = query_paginate(@chat_bases, params[:page])
- end
-
- render json: @chat_bases
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- chat_query = {}
- params.each do |param|
- next unless param[0] == "chat_name"
- next unless param[1] != "null" && param[1].length > 0
-
- chat_query.merge!({ param[0] => param[1] })
- end
-
- final_query = nil
-
- if chat_query["chat_name"]
- final_query = ChatBase.where("chat_name LIKE ?", "%#{chat_query["chat_name"]}%")
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at], [])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /chat_bases/1
- def show
- if !check_user_in_chat(@chat_basis.id)
- if !check_perms_query!(get_user_roles.perms_chat)
- return
- end
- end
- render json: @chat_basis
- end
-
- # Checks if a user has an open ```ChatBase``` with the system user.
- def has_system_notifs
- if !check_perms_query!(get_user_roles.perms_chat)
- return
- end
- notifs = ChatBase.where(chat_name: "private_chat_system_#{params[:user_id]}")
-
- if notifs.count > 0
- render json: notifs.first, status: :ok and return
- end
-
- render json: { :error => "User has no system chat." }, status: 404
- end
-
- # POST /chat_bases
- def create
- if !check_perms_write!(get_user_roles.perms_chat)
- return
- end
- if params[:chat_name].include?("private_chat_")
- nameDisect = params[:chat_name].split("_")
- inverted_name = "private_chat_#{nameDisect[3]}_#{nameDisect[2]}"
- nameExists = ChatBase.where(chat_name: params[:chat_name])
- invertedExists = ChatBase.where(chat_name: inverted_name)
-
- if nameExists.count > 0 || invertedExists.count > 0
- render json: { error: "Chat already exists" }, status: :unprocessable_entity
- else
- @chat_basis = ChatBase.new(
- chat_name: params[:chat_name],
- isGroup: params[:isGroup],
- isReadOnly: params[:isReadOnly].nil? ? false : params[:isReadOnly],
- )
- pri_key, pub_key = EduAppUtils::EncryptUtils::gen_key_pair(@chat_basis.id)
- @chat_basis.private_key = pri_key
- @chat_basis.public_key = pub_key
-
- if @chat_basis.save
- render json: @chat_basis, status: :created, location: @chat_basis
- else
- render json: @chat_basis.errors, status: :unprocessable_entity
- end
- end
- else
- @chat_basis = ChatBase.new(
- chat_name: params[:chat_name],
- isGroup: params[:isGroup],
- isReadOnly: params[:isReadOnly].nil? ? false : params[:isReadOnly],
- )
- pri_key, pub_key = EduAppUtils::EncryptUtils::gen_key_pair(@chat_basis.id)
- @chat_basis.private_key = pri_key
- @chat_basis.public_key = pub_key
-
- if @chat_basis.save
- render json: @chat_basis, status: :created, location: @chat_basis
- else
- render json: @chat_basis.errors, status: :unprocessable_entity
- end
- end
- end
-
- # PUT /chat_bases/1
- def update
- if !check_perms_update!(get_user_roles.perms_chat, false, :null)
- return
- end
- if @chat_basis.update(chat_basis_params)
- render json: @chat_basis
- else
- render json: @chat_basis.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /chat_bases/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_chat, false, :null)
- return
- end
- @chat_basis.destroy
- end
-
- private
-
- # Checks if a user is in a certain ```ChatBase```.
- def check_user_in_chat(chat_base_id)
- if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name === "eduapp_admin"
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_chat_basis
- @chat_basis = ChatBase.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def chat_basis_params
- params.require(:chat_basis).permit(:chat_name, :isGroup)
- end
-end
+class ChatBasesController < ApplicationController
+ before_action :set_chat_basis, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ require "edu_app_utils/encrypt_utils"
+
+ # GET /chat_bases
+ def index
+ wants_complete_chat = false
+
+ # Made to return all necessary information for a chat.
+ if params[:complete_chat_for]
+ wants_complete_chat = true
+ if !check_user_in_chat(params[:complete_chat_for])
+ return
+ end
+ chatBase = ChatBase.find(params[:complete_chat_for])
+ chat = chatBase.serializable_hash(:except => [:created_at, :updated_at])
+ other_participants = ChatParticipant.where(chat_base_id: params[:complete_chat_for])
+
+ # Not the best way, but a way to track readed chats
+ chatBase.chat_participants.where(user_id: @current_user).first.update_attribute(:last_seen, DateTime.now)
+
+ participants = []
+ other_participants.each do |participant|
+ p = UserInfo.where(user_id: participant.user_id).first.serializable_hash(:only => [:profile_image, :user_name], :include => [:user])
+ p.merge!({ isChatAdmin: participant.isChatAdmin })
+ participants.push(p)
+ end
+
+ # Be able to gather the counterpart info even if they left the chat
+ if chat["chat_name"].include?("private_chat_")
+ if participants.length < 2
+ name_disect = chat["chat_name"].split("_")
+ name_disect.delete("private")
+ name_disect.delete("chat")
+
+ chat_counterpart_id = name_disect[0] == participants[0]["user"]["id"] ? name_disect[1] : name_disect[0]
+ chat_counterpart = UserInfo.where(user_id: chat_counterpart_id).first.serializable_hash(:only => [:profile_image, :user_name], :include => [:user])
+ participants.push(chat_counterpart)
+ end
+ end
+
+ @chat_bases = { chat: chat, participants: participants }
+ else
+ if !check_perms_all!(get_user_roles.perms_chat)
+ return
+ end
+ @chat_bases = ChatBase.all
+ end
+
+ if !wants_complete_chat
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ order = JSON.parse(Base64.decode64(params[:order]))
+ order["field"] = order["field"] == "name" ? "chat_name" : order["field"]
+ @chat_bases = @chat_bases.order({ order["field"] => order["order"] == "asc" ? :asc : :desc })
+ else
+ @chat_bases = @chat_bases.order(chat_name: :asc)
+ end
+ end
+
+ if params[:page]
+ @chat_bases = query_paginate(@chat_bases, params[:page])
+ end
+
+ render json: @chat_bases
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ chat_query = {}
+ params.each do |param|
+ next unless param[0] == "chat_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ chat_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = nil
+
+ if chat_query["chat_name"]
+ final_query = ChatBase.where("chat_name LIKE ?", "%#{chat_query["chat_name"]}%")
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at], [])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /chat_bases/1
+ def show
+ if !check_user_in_chat(@chat_basis.id)
+ if !check_perms_query!(get_user_roles.perms_chat)
+ return
+ end
+ end
+ render json: @chat_basis
+ end
+
+ # Checks if a user has an open ```ChatBase``` with the system user.
+ def has_system_notifs
+ if !check_perms_query!(get_user_roles.perms_chat)
+ return
+ end
+ notifs = ChatBase.where(chat_name: "private_chat_system_#{params[:user_id]}")
+
+ if notifs.count > 0
+ render json: notifs.first, status: :ok and return
+ end
+
+ render json: { :error => "User has no system chat." }, status: 404
+ end
+
+ # POST /chat_bases
+ def create
+ if !check_perms_write!(get_user_roles.perms_chat)
+ return
+ end
+ if params[:chat_name].include?("private_chat_")
+ nameDisect = params[:chat_name].split("_")
+ inverted_name = "private_chat_#{nameDisect[3]}_#{nameDisect[2]}"
+ nameExists = ChatBase.where(chat_name: params[:chat_name])
+ invertedExists = ChatBase.where(chat_name: inverted_name)
+
+ if nameExists.count > 0 || invertedExists.count > 0
+ return render json: { error: "Chat already exists" }, status: :unprocessable_entity
+ end
+ @chat_basis = ChatBase.new(
+ chat_name: params[:chat_name],
+ isGroup: params[:isGroup],
+ isReadOnly: params[:isReadOnly].nil? ? false : params[:isReadOnly],
+ )
+ pri_key, pub_key = EduAppUtils::EncryptUtils::gen_key_pair(@chat_basis.id)
+ @chat_basis.private_key = pri_key
+ @chat_basis.public_key = pub_key
+
+ if @chat_basis.save
+ render json: @chat_basis, status: :created, location: @chat_basis
+ else
+ render json: @chat_basis.errors, status: :unprocessable_entity
+ end
+ else
+ @chat_basis = ChatBase.new(
+ chat_name: params[:chat_name],
+ isGroup: params[:isGroup],
+ isReadOnly: params[:isReadOnly].nil? ? false : params[:isReadOnly],
+ )
+ pri_key, pub_key = EduAppUtils::EncryptUtils::gen_key_pair(@chat_basis.id)
+ @chat_basis.private_key = pri_key
+ @chat_basis.public_key = pub_key
+
+ if @chat_basis.save
+ render json: @chat_basis, status: :created, location: @chat_basis
+ else
+ render json: @chat_basis.errors, status: :unprocessable_entity
+ end
+ end
+ end
+
+ # PUT /chat_bases/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_chat, false, :null)
+ return
+ end
+ if @chat_basis.update(chat_basis_params)
+ render json: @chat_basis
+ else
+ render json: @chat_basis.errors, status: :unprocessable_entity
+ end
+ end
+
+ # # PUT /chat_bases/1/read
+ # def read
+ # if !check_perms_update!(get_user_roles.perms_chat, false, :null)
+ # return
+ # end
+ # @chat_basis.participants.where(user_id: @current_user).first.update_attribute(:last_seen, DateTime.now())
+ # render json: {read: DateTime.now()}
+ # end
+
+ # DELETE /chat_bases/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_chat, false, :null)
+ return
+ end
+ @subject = Subject.find_by(chat_link: @chat_basis.id)
+ if @subject.present?
+ @subject.update(chat_link: nil)
+ @subject.save
+ end
+
+ @chat_basis.destroy
+ end
+
+ private
+
+ # Checks if a user is in a certain ```ChatBase```.
+ def check_user_in_chat(chat_base_id)
+ if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name === "eduapp_admin"
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_chat_basis
+ @chat_basis = ChatBase.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def chat_basis_params
+ params.require(:chat_basis).permit(:chat_name, :isGroup)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/chat_messages_controller.rb b/backend/eduapp_db/app/controllers/chat_messages_controller.rb
index f3f953e0..6d446e8f 100644
--- a/backend/eduapp_db/app/controllers/chat_messages_controller.rb
+++ b/backend/eduapp_db/app/controllers/chat_messages_controller.rb
@@ -1,91 +1,91 @@
-class ChatMessagesController < ApplicationController
- before_action :set_chat_message, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /chat_messages
- def index
- if params[:chat_base_id]
- if !check_user_in_chat(params[:chat_base_id])
- return deny_perms_access!
- end
- @chat_messages = ChatMessage.order(send_date: :asc).where(chat_base_id: params[:chat_base_id])
- else
- if !check_perms_all!(get_user_roles.perms_message)
- return
- end
- @chat_messages = ChatMessage.all
- end
-
- if params[:page]
- @chat_messages = query_paginate(@chat_messages, params[:page])
- end
-
- render json: @chat_messages
- end
-
- # GET /chat_messages/1
- def show
- if !check_perms_query!(get_user_roles.perms_message)
- return
- end
- render json: @chat_message
- end
-
- # POST /chat_messages
- def create
- if !check_user_in_chat(params[:chat_base_id])
- if !check_perms_write!(get_user_roles.perms_message)
- return
- end
- end
- @chat_message = ChatMessage.new(chat_message_params)
-
- if @chat_message.save
- render json: @chat_message, status: :created, location: @chat_message
- else
- render json: @chat_message.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /chat_messages/1
- def update
- if !check_perms_update!(get_user_roles.perms_message, false, :null) && !check_action_owner!(@chat_message.user_id)
- return
- end
-
- if @chat_message.update(chat_message_params)
- render json: @chat_message
- else
- render json: @chat_message.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /chat_messages/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_roles, false, :null) && !check_user_in_chat(params[:id])
- return
- end
- @chat_message.destroy
- end
-
- private
-
- # Checks if a user is in a certain ```ChatBase```.
- def check_user_in_chat(chat_base_id)
- if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name == "eduapp_admin"
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_chat_message
- @chat_message = ChatMessage.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def chat_message_params
- params.require(:chat_message).permit(:chat_base_id, :user_id, :message, :send_date)
- end
-end
+class ChatMessagesController < ApplicationController
+ before_action :set_chat_message, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /chat_messages
+ def index
+ if params[:chat_base_id]
+ if !check_user_in_chat(params[:chat_base_id])
+ return deny_perms_access!
+ end
+ @chat_messages = ChatMessage.order(send_date: :asc).where(chat_base_id: params[:chat_base_id])
+ else
+ if !check_perms_all!(get_user_roles.perms_message)
+ return
+ end
+ @chat_messages = ChatMessage.all
+ end
+
+ if params[:page]
+ @chat_messages = query_paginate(@chat_messages, params[:page])
+ end
+
+ render json: @chat_messages
+ end
+
+ # GET /chat_messages/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_message)
+ return
+ end
+ render json: @chat_message
+ end
+
+ # POST /chat_messages
+ def create
+ if !check_user_in_chat(params[:chat_base_id])
+ if !check_perms_write!(get_user_roles.perms_message)
+ return
+ end
+ end
+ @chat_message = ChatMessage.new(chat_message_params)
+
+ if @chat_message.save
+ render json: @chat_message, status: :created, location: @chat_message
+ else
+ render json: @chat_message.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /chat_messages/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_message, false, :null) && !check_action_owner!(@chat_message.user_id)
+ return
+ end
+
+ if @chat_message.update(chat_message_params)
+ render json: @chat_message
+ else
+ render json: @chat_message.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /chat_messages/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_roles, false, :null) && !check_user_in_chat(params[:id])
+ return
+ end
+ @chat_message.destroy
+ end
+
+ private
+
+ # Checks if a user is in a certain ```ChatBase```.
+ def check_user_in_chat(chat_base_id)
+ if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name == "eduapp_admin"
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_chat_message
+ @chat_message = ChatMessage.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def chat_message_params
+ params.require(:chat_message).permit(:chat_base_id, :user_id, :message, :send_date)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/chat_participants_controller.rb b/backend/eduapp_db/app/controllers/chat_participants_controller.rb
index eba8d8fb..f2bdbb69 100644
--- a/backend/eduapp_db/app/controllers/chat_participants_controller.rb
+++ b/backend/eduapp_db/app/controllers/chat_participants_controller.rb
@@ -1,177 +1,183 @@
-class ChatParticipantsController < ApplicationController
- before_action :set_chat_participant, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /chat_participants
- def index
- if params[:user_id]
- if !check_perms_query_self!(get_user_roles.perms_chat_participants, params[:user_id])
- return
- end
- @participants = ChatParticipant.where(user_id: params[:user_id])
- elsif params[:chats_for]
- if !check_perms_query_self!(get_user_roles.perms_chat_participants, params[:chats_for])
- return
- end
- user_chats = ChatParticipant.where(user_id: params[:chats_for])
-
- final_chats = []
- user_chats.each do |chatp|
- chat = ChatBase.find(chatp.chat_base_id).serializable_hash(:except => [:private_key, :public_key, :created_at, :updated_at])
- if chat["chat_name"].include?("private_chat_")
- chat_counterpart = ChatParticipant.where(chat_base_id: chat["id"]).where.not(user_id: params[:chats_for]).first
-
- # Be able to gather the counterpart info even if they left the chat
- if chat_counterpart == nil
- name_disect = chat["chat_name"].split("_")
- name_disect.delete("private")
- name_disect.delete("chat")
-
- chat_counterpart_id = name_disect[0] == params[:chat_for] ? name_disect[1] : name_disect[0]
- chat_counterpart = UserInfo.where(user_id: chat_counterpart_id).first
- end
-
- final_chats.push({
- chat_info: chat,
- chat_participant: UserInfo.where(user_id: chat_counterpart.user_id).first.serializable_hash(:except => [:created_at, :updated_at, :user_role_id, :googleid]),
- })
- else
- final_chats.push({ chat_info: chat })
- end
- end
- @participants = { personal_chats: final_chats }
- elsif params[:chat_id]
- if !check_perms_query!(get_user_roles.perms_chat_participants)
- return
- end
- @participants = ChatParticipant.where(chat_base_id: params[:chat_id])
- else
- if !check_perms_all!(get_user_roles.perms_chat_participants)
- return
- end
- @participants = ChatParticipant.all
- end
-
- if params[:page]
- @participants = query_paginate(@participants, params[:page])
- @participants[:current_page] = serialize_each(@participants[:current_page], [:created_at, :updated_at, :user_id, :chat_base_id], [:user, :chat_base])
- end
-
-
- render json: @participants
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- parts_query = {}
- params.each do |param|
- next unless param[0] == "email" || param[0] == "chat_name"
- next unless param[1] != "null" && param[1].length > 0
-
- parts_query.merge!({ param[0] => param[1] })
- end
-
- final_query = nil
-
- if parts_query["email"]
- final_query = ChatParticipant.where(user_id: User.where("email LIKE ?", "%#{parts_query["email"]}%"))
- end
-
- if parts_query["chat_name"]
- if !final_query.nil?
- final_query = final_query.where(chat_base_id: ChatBase.where("chat_name LIKE ?", "%#{parts_query["chat_name"]}%"))
- else
- final_query = ChatParticipant.where(chat_base_id: ChatBase.where("chat_name LIKE ?", "%#{parts_query["chat_name"]}%"))
- end
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :chat_base_base], [:chat_base, :user])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /chat_participants/1
- def show
- if !check_perms_query!(get_user_roles.perms_chat_participants)
- return
- end
- render json: @chat_participant
- end
-
- # POST /chat_participants
- def create
- if !check_perms_write!(get_user_roles.perms_chat_participants)
- return
- end
- @chat_participant = ChatParticipant.new(chat_participant_params)
- if @chat_participant.save
- render json: @chat_participant, status: :created, location: @chat_participant
- else
- render json: @chat_participant.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /chat_participants/1
- def update
- if !check_perms_update!(get_user_roles.perms_chat_participants, false, :null)
- return
- end
-
- if @chat_participant.update(chat_participant_params)
- render json: @chat_participant
- else
- render json: @chat_participant.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /chat_participants/1
- def destroy
- return if !check_perms_delete!(get_user_roles.perms_chat_participants, false, :null)
-
- @chat_participant.destroy
- end
-
- # Removes a user from a chat, and deletes the ```ChatBase``` if
- # no more ```ChatParticipant``` are linked to it.
- def remove_participant
- @chat_participant = ChatParticipant.where(user_id: params[:user_id], chat_base_id: params[:chat_base_id])
- if @chat_participant.length > 0
- @chat_participant.first.destroy
-
- if ChatParticipant.where(chat_base_id: params[:chat_base_id]).length < 1
- ChatMessage.where(chat_base_id: params[:chat_base_id]).each do |m|
- m.destroy
- end
- ChatBase.find(params[:chat_base_id]).destroy
- end
- return
- end
- return render json: { error: "Participant not found." }, status: 404
- end
-
- private
-
- # Checks if a user is in a certain ```ChatBase```.
- def check_user_in_chat(chat_base_id)
- if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name == "eduapp_admin"
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_chat_participant
- @chat_participant = ChatParticipant.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def chat_participant_params
- params.require(:chat_participant).permit(:chat_base_id, :user_id, :isChatAdmin)
- end
-end
+class ChatParticipantsController < ApplicationController
+ before_action :set_chat_participant, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /chat_participants
+ def index
+ if params[:user_id]
+ if !check_perms_query_self!(get_user_roles.perms_chat_participants, params[:user_id])
+ return
+ end
+ @participants = ChatParticipant.where(user_id: params[:user_id])
+ elsif params[:chats_for]
+ if !check_perms_query_self!(get_user_roles.perms_chat_participants, params[:chats_for])
+ return
+ end
+ user_chats = ChatParticipant.where(user_id: params[:chats_for])
+
+ final_chats = []
+ user_chats.each do |chatp|
+ chatBase = ChatBase.find(chatp.chat_base_id)
+ lastMessage = chatBase.chat_messages.last || ChatMessage.new(send_date: chatBase.created_at)
+ chatSelfCounterpart = chatBase.chat_participants.where({user_id: params[:chats_for]}).first
+ chat = chatBase.serializable_hash(:except => [:private_key, :public_key, :created_at, :updated_at]).merge({
+ last_message: lastMessage.serializable_hash,
+ self_counterpart: chatSelfCounterpart.serializable_hash
+ })
+ if chat["chat_name"].include?("private_chat_")
+ chat_counterpart = ChatParticipant.where(chat_base_id: chat["id"]).where.not(user_id: params[:chats_for]).first
+
+ # Be able to gather the counterpart info even if they left the chat
+ if chat_counterpart == nil
+ name_disect = chat["chat_name"].split("_")
+ name_disect.delete("private")
+ name_disect.delete("chat")
+
+ chat_counterpart_id = name_disect[0] == params[:chat_for] ? name_disect[1] : name_disect[0]
+ chat_counterpart = UserInfo.where(user_id: chat_counterpart_id).first
+ end
+
+ final_chats.push({
+ chat_info: chat,
+ chat_participant: UserInfo.where(user_id: chat_counterpart.user_id).first.serializable_hash(:except => [:created_at, :updated_at, :user_role_id, :googleid]), # .merge(chat_counterpart.serializable_hash),
+ })
+ else
+ final_chats.push({ chat_info: chat })
+ end
+ end
+ @participants = { personal_chats: final_chats }
+ elsif params[:chat_id]
+ if !check_perms_query!(get_user_roles.perms_chat_participants)
+ return
+ end
+ @participants = ChatParticipant.where(chat_base_id: params[:chat_id])
+ else
+ if !check_perms_all!(get_user_roles.perms_chat_participants)
+ return
+ end
+ @participants = ChatParticipant.all
+ end
+
+ if params[:page]
+ @participants = query_paginate(@participants, params[:page])
+ @participants[:current_page] = serialize_each(@participants[:current_page], [:created_at, :updated_at, :user_id, :chat_base_id], [:user, :chat_base])
+ end
+
+
+ render json: @participants
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ parts_query = {}
+ params.each do |param|
+ next unless param[0] == "email" || param[0] == "chat_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ parts_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = nil
+
+ if parts_query["email"]
+ final_query = ChatParticipant.where(user_id: User.where("email LIKE ?", "%#{parts_query["email"]}%"))
+ end
+
+ if parts_query["chat_name"]
+ if !final_query.nil?
+ final_query = final_query.where(chat_base_id: ChatBase.where("chat_name LIKE ?", "%#{parts_query["chat_name"]}%"))
+ else
+ final_query = ChatParticipant.where(chat_base_id: ChatBase.where("chat_name LIKE ?", "%#{parts_query["chat_name"]}%"))
+ end
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :chat_base_base], [:chat_base, :user])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /chat_participants/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_chat_participants)
+ return
+ end
+ render json: @chat_participant
+ end
+
+ # POST /chat_participants
+ def create
+ if !check_perms_write!(get_user_roles.perms_chat_participants)
+ return
+ end
+ @chat_participant = ChatParticipant.new(chat_participant_params)
+ if @chat_participant.save
+ render json: @chat_participant, status: :created, location: @chat_participant
+ else
+ render json: @chat_participant.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /chat_participants/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_chat_participants, false, :null)
+ return
+ end
+
+ if @chat_participant.update(chat_participant_params)
+ render json: @chat_participant
+ else
+ render json: @chat_participant.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /chat_participants/1
+ def destroy
+ return if !check_perms_delete!(get_user_roles.perms_chat_participants, false, :null)
+
+ @chat_participant.destroy
+ end
+
+ # Removes a user from a chat, and deletes the ```ChatBase``` if
+ # no more ```ChatParticipant``` are linked to it.
+ def remove_participant
+ @chat_participant = ChatParticipant.where(user_id: params[:user_id], chat_base_id: params[:chat_base_id])
+ if @chat_participant.length > 0
+ @chat_participant.first.destroy
+
+ if ChatParticipant.where(chat_base_id: params[:chat_base_id]).length < 1
+ ChatMessage.where(chat_base_id: params[:chat_base_id]).each do |m|
+ m.destroy
+ end
+ ChatBase.find(params[:chat_base_id]).destroy
+ end
+ return
+ end
+ return render json: { error: "Participant not found." }, status: 404
+ end
+
+ private
+
+ # Checks if a user is in a certain ```ChatBase```.
+ def check_user_in_chat(chat_base_id)
+ if ChatParticipant.where(user_id: @current_user, chat_base_id: chat_base_id).count > 0 || get_user_roles.name == "eduapp_admin"
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_chat_participant
+ @chat_participant = ChatParticipant.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def chat_participant_params
+ params.require(:chat_participant).permit(:chat_base_id, :user_id, :isChatAdmin)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/courses_controller.rb b/backend/eduapp_db/app/controllers/courses_controller.rb
index 71dc9cbd..b82bc1cf 100644
--- a/backend/eduapp_db/app/controllers/courses_controller.rb
+++ b/backend/eduapp_db/app/controllers/courses_controller.rb
@@ -1,132 +1,135 @@
-class CoursesController < ApplicationController
- before_action :set_course, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /courses
- def index
- is_name = false
- if params[:user_id]
- if !check_perms_query_self!(get_user_roles.perms_course, params[:user_id])
- return
- end
- @courses = Course.where(id: Tuition.where(user_id: params[:user_id]))
- elsif params[:name]
- # TODO: HANDLE PERMISSIONS FOR NAME QUERIES
- is_name = true
- @courses = Course.where(name: params[:name]).first
- else
- if !check_perms_all!(get_user_roles.perms_course)
- return
- end
- @courses = Course.all
- end
-
- if !is_name
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @courses = @courses.order(parse_filter_order(params[:order]))
- else
- @courses = @courses.order(name: :asc)
- end
- end
-
- if params[:page]
- @courses = query_paginate(@courses, params[:page])
- @courses[:current_page] = serialize_each(@courses[:current_page], [:created_at, :updated_at, :institution_id], [:institution])
- end
-
- render json: @courses
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- course_query = {}
- params.each do |param|
- next unless param[0] == "id" || param[0] == "name"
- next unless param[1] != "null" && param[1].length > 0
-
- course_query.merge!({ param[0] => param[1] })
- end
-
- final_query = params[:extras] ? filter_extrafields(params[:extras], Course) : nil
-
- if course_query["id"]
- ids = []
- Course.all.each do |c|
- ids << c.id if c.id.to_s =~ /^#{course_query["id"]}.*$/
- end
- final_query = !final_query.nil? ? final_query.where(id: ids) : Course.where(id: ids)
- end
-
- if course_query["name"]
- if !final_query.nil?
- final_query = final_query.where("name LIKE ?", "%#{course_query["name"]}%")
- else
- final_query = Course.where("name LIKE ?", "%#{course_query["name"]}%")
- end
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :institution_id], [:institution])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /courses/1
- def show
- if !check_perms_query!(get_user_roles.perms_course)
- return
- end
- render json: @course
- end
-
- # POST /courses
- def create
- if !check_perms_write!(get_user_roles.perms_course)
- return
- end
- @course = Course.new(course_params)
-
- if @course.save
- render json: @course, status: :created, location: @course
- else
- render json: @course.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /courses/1
- def update
- if !check_perms_update!(get_user_roles.perms_course, false, :null)
- return
- end
- if @course.update(course_params)
- render json: @course
- else
- render json: @course.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /courses/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_course, false, :null)
- return
- end
- @course.destroy
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_course
- @course = Course.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def course_params
- params.permit(:institution_id, :name)
- end
-end
+class CoursesController < ApplicationController
+ before_action :set_course, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /courses
+ def index
+ is_name = false
+ if params[:user_id]
+ if !check_perms_query_self!(get_user_roles.perms_course, params[:user_id])
+ return
+ end
+ @courses = Course.where(id: Tuition.where(user_id: params[:user_id]))
+ elsif params[:name]
+ # TODO: HANDLE PERMISSIONS FOR NAME QUERIES
+ is_name = true
+ @courses = Course.where('name ilike ?', "%#{params[:name]}%")
+ elsif params[:id]
+ # TODO: HANDLE PERMISSIONS FOR NAME QUERIES
+ @courses = Course.where('id::text ilike ?', "%#{params[:id]}%")
+ else
+ if !check_perms_all!(get_user_roles.perms_course)
+ return
+ end
+ @courses = Course.all
+ end
+
+ if !is_name
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ @courses = @courses.order(parse_filter_order(params[:order]))
+ else
+ @courses = @courses.order(name: :asc)
+ end
+ end
+
+ if params[:page]
+ @courses = query_paginate(@courses, params[:page])
+ @courses[:current_page] = serialize_each(@courses[:current_page], [:created_at, :updated_at, :institution_id], [:institution])
+ end
+
+ render json: @courses
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ course_query = {}
+ params.each do |param|
+ next unless param[0] == "id" || param[0] == "name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ course_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = params[:extras] ? filter_extrafields(params[:extras], Course) : nil
+
+ if course_query["id"]
+ ids = []
+ Course.all.each do |c|
+ ids << c.id if c.id.to_s =~ /^#{course_query["id"]}.*$/
+ end
+ final_query = !final_query.nil? ? final_query.where(id: ids) : Course.where(id: ids)
+ end
+
+ if course_query["name"]
+ if !final_query.nil?
+ final_query = final_query.where("name LIKE ?", "%#{course_query["name"]}%")
+ else
+ final_query = Course.where("name LIKE ?", "%#{course_query["name"]}%")
+ end
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :institution_id], [:institution])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /courses/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_course)
+ return
+ end
+ render json: @course
+ end
+
+ # POST /courses
+ def create
+ if !check_perms_write!(get_user_roles.perms_course)
+ return
+ end
+ @course = Course.new(course_params)
+
+ if @course.save
+ render json: @course, status: :created, location: @course
+ else
+ render json: @course.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /courses/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_course, false, :null)
+ return
+ end
+ if @course.update(course_params)
+ render json: @course
+ else
+ render json: @course.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /courses/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_course, false, :null)
+ return
+ end
+ @course.destroy
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_course
+ @course = Course.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def course_params
+ params.permit(:institution_id, :name)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/eduapp_user_sessions_controller.rb b/backend/eduapp_db/app/controllers/eduapp_user_sessions_controller.rb
index e1c4f11d..5e29be2a 100644
--- a/backend/eduapp_db/app/controllers/eduapp_user_sessions_controller.rb
+++ b/backend/eduapp_db/app/controllers/eduapp_user_sessions_controller.rb
@@ -1,295 +1,396 @@
-class EduappUserSessionsController < ApplicationController
- before_action :set_eduapp_user_session, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- require "date"
- require "securerandom"
-
- # GET /eduapp_user_sessions
- def index
- if params[:subject_id]
- if !subject_in_user_course(params[:subject_id])
- return deny_perms_access!
- end
- @eduapp_user_sessions = EduappUserSession.where(subject_id: params[:subject_id])
- else
- if !check_perms_all!(get_user_roles.perms_sessions)
- return
- end
- @eduapp_user_sessions = EduappUserSession.all
- end
-
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @eduapp_user_sessions = @eduapp_user_sessions.order(parse_filter_order(params[:order]))
- else
- @eduapp_user_sessions = @eduapp_user_sessions.order(session_name: :asc)
- end
-
- if params[:page]
- @eduapp_user_sessions = query_paginate(@eduapp_user_sessions, params[:page])
- @eduapp_user_sessions[:current_page] = serialize_each(@eduapp_user_sessions[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
- end
-
- render json: @eduapp_user_sessions
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- sessions_query = {}
- subject_query = {}
- params.each do |param|
- next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "eduapp_user_session"
- next unless param[1] != "null" && param[1].length > 0
-
- query = { param[0] => param[1] }
- case param[0]
- when "id", "session_name", "streaming_platform", "resources_platform", "session_chat_id"
- sessions_query.merge!(query)
- when "subject_name"
- subject_query.merge!(query)
- end
- end
-
- final_query = params[:extras] ? filter_extrafields(params[:extras], EduappUserSession) : nil
-
- if !sessions_query.empty?
- query = !final_query.nil? ? final_query : nil
-
- if sessions_query["id"]
- ids = []
- EduappUserSession.all.each do |s|
- ids << s.id if s.id.to_s =~ /^#{sessions_query["id"]}.*$/
- end
- query = EduappUserSession.where(id: ids)
- end
-
- if sessions_query["session_name"]
- if !query.nil?
- query = query.where("session_name LIKE ?", "%#{sessions_query["session_name"]}%")
- else
- query = EduappUserSession.where("session_name LIKE ?", "%#{sessions_query["session_name"]}%")
- end
- end
-
- if sessions_query["streaming_platform"]
- if !query.nil?
- query = query.where("streaming_platform LIKE ?", "%#{sessions_query["streaming_platform"]}%")
- else
- query = EduappUserSession.where("streaming_platform LIKE ?", "%#{sessions_query["streaming_platform"]}%")
- end
- end
-
- if sessions_query["resources_platform"]
- if !query.nil?
- query = query.where("resources_platform LIKE ?", "%#{sessions_query["resources_platform"]}%")
- else
- query = EduappUserSession.where("resources_platform LIKE ?", "%#{sessions_query["resources_platform"]}%")
- end
- end
-
- if sessions_query["session_chat_id"]
- if !query.nil?
- query = query.where("session_chat_id LIKE ?", "%#{sessions_query["session_chat_id"]}%")
- else
- query = EduappUserSession.where("session_chat_id LIKE ?", "%#{sessions_query["session_chat_id"]}%")
- end
- end
-
- final_query = query
- end
-
- if !final_query.nil? && !subject_query.empty?
- final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- elsif !subject_query.empty?
- final_query = EduappUserSession.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /eduapp_user_sessions/1
- def show
- if !check_perms_query!(get_user_roles.perms_sessions)
- return
- end
- render json: @eduapp_user_session
- end
-
- # POST /eduapp_user_sessions
- def create
- if !check_perms_write!(get_user_roles.perms_sessions)
- return
- end
- @eduapp_user_session = EduappUserSession.new(eduapp_user_session_params)
- if @eduapp_user_session.save
- render json: @eduapp_user_session, status: :created, location: @eduapp_user_session
- else
- render json: @eduapp_user_session.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /eduapp_user_sessions/1
- def update
- if !check_perms_update!(get_user_roles.perms_sessions, false, :null)
- return
- end
-
- if @eduapp_user_session.update(session_name: params[:session_name],
- session_start_date: params[:session_start_date],
- session_end_date: params[:session_end_date],
- streaming_platform: params[:streaming_platform],
- resources_platform: params[:resources_platform],
- session_chat_id: params[:session_chat_id],
- subject_id: params[:subject_id], batch_id: nil)
- render json: @eduapp_user_session
- else
- render json: @eduapp_user_session.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /eduapp_user_sessions/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_roles, false, :null)
- return
- end
- @eduapp_user_session.destroy
- end
-
- # Destroys a group of ```EduappUserSession``` created by the
- # batch loader.
- def destroy_batch
- EduappUserSession.where(batch_id: params[:batch_id]).destroy_all
- end
-
- # Creates a group of ```EduappUserSession``` based on many entries
- # and generates a new ```EduappUserSession``` entry for each.
- def session_batch_load
- days_added = 0
- weeks_passed = 0
- week_days_passed = 1
- first_week = true
-
- new_session_days = []
- cursor_date = params[:session_start_date].split("T")[0].to_date - 1
- last_cursor_date = cursor_date
-
- while days_added <= params[:diff_days]
- if !first_week
- if params[:week_repeat] > 0
- if cursor_date.strftime("%U").to_i != last_cursor_date.strftime("%U").to_i
- weeks_passed = 0 if weeks_passed >= params[:week_repeat]
- weeks_passed += 1
- if weeks_passed < params[:week_repeat]
- cursor_date = cursor_date + 7
- if cursor_date > params[:session_end_date].split("T")[0].to_date
- break
- end
- next
- end
- end
- end
- end
-
- if (params[:check_week_days][0] && cursor_date.monday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][1] && cursor_date.tuesday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][2] && cursor_date.wednesday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][3] && cursor_date.thursday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][4] && cursor_date.friday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][5] && cursor_date.saturday?)
- new_session_days.append(cursor_date)
- end
- if (params[:check_week_days][6] && cursor_date.sunday?)
- new_session_days.append(cursor_date)
- end
-
- days_added += 1
- last_cursor_date = cursor_date
- cursor_date = cursor_date + 1
- week_days_passed += 1
- if week_days_passed > 7
- first_week = false
- week_days_passed = 0
- end
- end
-
- session_start_time = params[:session_start_date].split("T")[1]
- session_end_time = params[:session_end_date].split("T")[1]
- batch_id = SecureRandom.uuid
- subjectId = Subject.where(id: params[:subject_id]).first.id
-
- new_session_days.each do |day|
- @eduapp_user_session = EduappUserSession.new(
- session_name: params[:session_name],
- session_start_date: day.to_s + "T" + session_start_time,
- session_end_date: day.to_s + "T" + session_end_time,
- resources_platform: params[:resources_platform],
- streaming_platform: params[:streaming_platform],
- session_chat_id: params[:session_chat_id],
- subject_id: subjectId,
- batch_id: batch_id,
- )
-
- if !@eduapp_user_session.save
- render json: @eduapp_user_session.errors, status: :unprocessable_entity and return
- end
- end
- render json: @eduapp_user_session
- end
-
- # Updates a group of ```EduappUserSession``` based on its batch identifier.
- def update_batch
- render json: { error: "No id provided" }, status: :unprocessable_entity and return if params[:batch_id].nil?
-
- sessionsToBeUpdated = EduappUserSession.where(batch_id: params[:batch_id])
- if sessionsToBeUpdated.update(
- session_name: params[:session_name],
- resources_platform: params[:resources_platform],
- streaming_platform: params[:streaming_platform],
- session_chat_id: params[:session_chat_id],
- subject_id: params[:subject_id],
- )
- render json: { message: "Successfully updated sessions" } and return
- else
- render json: { error: "Failed to update sessions" }, status: :unprocessable_entity and return
- end
- end
-
- private
-
- # Checks if ```Subject``` is present in the user's ```Course```.
- def subject_in_user_course(s_id)
- c_id = Subject.find(s_id).course_id
- if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_eduapp_user_session
- @eduapp_user_session = EduappUserSession.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def eduapp_user_session_params
- params.require(:eduapp_user_session).permit(:session_name, :session_start_date, :session_end_date, :streaming_platform, :resources_platform, :session_chat_id, :subject_id, :number_repeat, :check_week_days, :diff_days)
- end
-end
+class EduappUserSessionsController < ApplicationController
+ before_action :set_eduapp_user_session, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ require "date"
+ require "securerandom"
+
+ # GET /eduapp_user_sessions
+ def index
+ if params[:subject_id]
+ if !subject_in_user_course(params[:subject_id])
+ return deny_perms_access!
+ end
+ @eduapp_user_sessions = EduappUserSession.where(subject_id: params[:subject_id])
+ elsif params[:session_name]
+ # if !subject_in_user_course(params[:subject_id])
+ # return deny_perms_access!
+ # end
+ @eduapp_user_sessions = EduappUserSession.where('session_name ilike ?', "%#{params[:session_name]}%")
+ elsif params[:id]
+ # TODO: HANDLE PERMISSIONS FOR NAME QUERIES
+ @eduapp_user_sessions = EduappUserSession.where('id::text ilike ?', "%#{params[:id]}%")
+ elsif params[:streaming_platform]
+ # if !subject_in_user_course(params[:subject_id])
+ # return deny_perms_access!
+ # end
+ @eduapp_user_sessions = EduappUserSession.where('streaming_platform ilike ?', "%#{params[:streaming_platform]}%")
+ elsif params[:session_chat_id]
+ # if !subject_in_user_course(params[:subject_id])
+ # return deny_perms_access!
+ # end
+ @eduapp_user_sessions = EduappUserSession.where('session_chat_id::text ilike ?', "%#{params[:session_chat_id]}%")
+ elsif params[:subject_name]
+ # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
+ @eduapp_user_sessions = EduappUserSession.joins(:subject).where('subjects.name ilike ?', "%#{params[:subject_name]}%")
+ else
+ if !check_perms_all!(get_user_roles.perms_sessions)
+ return
+ end
+ @eduapp_user_sessions = EduappUserSession.all
+ end
+
+ order = !params[:order].nil? && JSON.parse(Base64.decode64(params[:order]))
+ if order && order["field"] != ""
+ if order["field"] == 'subject_name'
+ @eduapp_user_sessions = @eduapp_user_sessions.joins(:subject)
+ end
+ @eduapp_user_sessions = @eduapp_user_sessions.order(parse_filter_order(order, {'subject_name' => 'subjects.name'}))
+
+ else
+ @eduapp_user_sessions = @eduapp_user_sessions.order(session_name: :asc)
+ end
+
+ if params[:page]
+ @eduapp_user_sessions = query_paginate(@eduapp_user_sessions, params[:page])
+ @eduapp_user_sessions[:current_page] = serialize_each(@eduapp_user_sessions[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
+ end
+
+ render json: @eduapp_user_sessions
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ sessions_query = {}
+ subject_query = {}
+ params.each do |param|
+ next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "eduapp_user_session"
+ next unless param[1] != "null" && param[1].length > 0
+
+ query = { param[0] => param[1] }
+ case param[0]
+ when "id", "session_name", "streaming_platform", "resources_platform", "session_chat_id"
+ sessions_query.merge!(query)
+ when "subject_name"
+ subject_query.merge!(query)
+ end
+ end
+
+ final_query = params[:extras] ? filter_extrafields(params[:extras], EduappUserSession) : nil
+
+ if !sessions_query.empty?
+ query = !final_query.nil? ? final_query : nil
+
+ if sessions_query["id"]
+ ids = []
+ EduappUserSession.all.each do |s|
+ ids << s.id if s.id.to_s =~ /^#{sessions_query["id"]}.*$/
+ end
+ query = EduappUserSession.where(id: ids)
+ end
+
+ if sessions_query["session_name"]
+ if !query.nil?
+ query = query.where("session_name LIKE ?", "%#{sessions_query["session_name"]}%")
+ else
+ query = EduappUserSession.where("session_name LIKE ?", "%#{sessions_query["session_name"]}%")
+ end
+ end
+
+ if sessions_query["streaming_platform"]
+ if !query.nil?
+ query = query.where("streaming_platform LIKE ?", "%#{sessions_query["streaming_platform"]}%")
+ else
+ query = EduappUserSession.where("streaming_platform LIKE ?", "%#{sessions_query["streaming_platform"]}%")
+ end
+ end
+
+ if sessions_query["resources_platform"]
+ if !query.nil?
+ query = query.where("resources_platform LIKE ?", "%#{sessions_query["resources_platform"]}%")
+ else
+ query = EduappUserSession.where("resources_platform LIKE ?", "%#{sessions_query["resources_platform"]}%")
+ end
+ end
+
+ if sessions_query["session_chat_id"]
+ if !query.nil?
+ query = query.where("session_chat_id LIKE ?", "%#{sessions_query["session_chat_id"]}%")
+ else
+ query = EduappUserSession.where("session_chat_id LIKE ?", "%#{sessions_query["session_chat_id"]}%")
+ end
+ end
+
+ final_query = query
+ end
+
+ if !final_query.nil? && !subject_query.empty?
+ final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ elsif !subject_query.empty?
+ final_query = EduappUserSession.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :subject_id], [:subject])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /eduapp_user_sessions/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_sessions, false) && !check_perms_query_self!(get_user_roles.perms_subjects, current_user)
+ deny_perms_access!
+ return
+ end
+ render json: @eduapp_user_session
+ end
+
+ # POST /eduapp_user_sessions
+ def create
+ if !check_perms_write!(get_user_roles.perms_sessions)
+ return
+ end
+ @eduapp_user_session = EduappUserSession.new(permitted_params)
+ if @eduapp_user_session.save
+ render json: @eduapp_user_session, status: :created, location: @eduapp_user_session
+ else
+ render json: @eduapp_user_session.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /eduapp_user_sessions/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_sessions, false, :null)
+ return
+ end
+
+ if @eduapp_user_session.update(session_name: params[:session_name],
+ session_start_date: params[:session_start_date],
+ session_end_date: params[:session_end_date],
+ streaming_platform: params[:streaming_platform],
+ resources_platform: params[:resources_platform],
+ session_chat_id: params[:session_chat_id],
+ subject_id: params[:subject_id], batch_id: nil)
+ render json: @eduapp_user_session
+ else
+ render json: @eduapp_user_session.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /eduapp_user_sessions/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_roles, false, :null)
+ return
+ end
+ @eduapp_user_session.destroy
+ end
+
+ # Destroys a group of ```EduappUserSession``` created by the
+ # batch loader.
+ def destroy_batch
+ EduappUserSession.where(batch_id: params[:batch_id]).destroy_all
+ end
+
+ # Creates a group of ```EduappUserSession``` based on many entries
+ # and generates a new ```EduappUserSession``` entry for each.
+ def session_batch_load
+
+ set_new_session_days
+
+ session_start_time = params[:session_start_date].split("T")[1]
+ session_end_time = params[:session_end_date].split("T")[1]
+ batch_id = SecureRandom.uuid
+ subjectId = Subject.where(id: params[:subject_id]).first.id
+
+ @new_session_days.each do |day|
+ @eduapp_user_session = EduappUserSession.new(
+ session_name: params[:session_name],
+ session_start_date: day.to_s + "T" + session_start_time,
+ session_end_date: day.to_s + "T" + session_end_time,
+ resources_platform: params[:resources_platform],
+ streaming_platform: params[:streaming_platform],
+ session_chat_id: params[:session_chat_id],
+ subject_id: subjectId,
+ batch_id: batch_id,
+ )
+
+ if !@eduapp_user_session.save
+ render json: @eduapp_user_session.errors, status: :unprocessable_entity and return
+ end
+ end
+ render json: @eduapp_user_session
+ end
+
+ # Updates a group of ```EduappUserSession``` based on its batch identifier.
+ def update_batch
+ render json: { error: "No id provided" }, status: :unprocessable_entity and return if params[:batch_id].nil?
+
+ sessionsToBeUpdated = EduappUserSession.where(batch_id: params[:batch_id])
+ if sessionsToBeUpdated.update(
+ session_name: params[:session_name],
+ resources_platform: params[:resources_platform],
+ streaming_platform: params[:streaming_platform],
+ session_chat_id: params[:session_chat_id],
+ subject_id: params[:subject_id],
+ )
+ render json: { message: "Successfully updated sessions" } and return
+ else
+ render json: { error: "Failed to update sessions" }, status: :unprocessable_entity and return
+ end
+ end
+
+ def upload_single_sessions
+ if !check_perms_write!(get_user_roles.perms_sessions)
+ return
+ end
+ subjects = Subject.where(external_id: permitted_params[:subject_id])
+
+ if subjects.size.zero?
+ render json: {errors: "No external id"}, status: :bad_request
+ else
+ params['eduapp_user_session']['subject_id'] = subjects.first.id
+ session = EduappUserSession.new(permitted_params.except(:session_chat_id) )
+ if session.save
+ render json: session, status: :created, location: session
+ else
+ render json: session.errors, status: :unprocessable_entity
+ end
+ end
+ end
+
+ def upload_batch_sessions
+
+ if !check_perms_write!(get_user_roles.perms_sessions)
+ return
+ end
+ subjects = Subject.where(external_id: permitted_params[:subject_id])
+
+ if subjects.size.zero?
+ render json: {errors: "No external id"}, status: :bad_request
+ else
+
+ subject_id = subjects.first.id
+
+ set_new_session_days
+
+ session_start_time = params[:session_start_date].split("T")[1]
+ session_end_time = params[:session_end_date].split("T")[1]
+ batch_id = SecureRandom.uuid
+ @new_session_days.each do |day|
+ @eduapp_user_session = EduappUserSession.new(
+ session_name: params[:session_name],
+ session_start_date: day.to_s + "T" + session_start_time,
+ session_end_date: day.to_s + "T" + session_end_time,
+ resources_platform: params[:resources_platform],
+ streaming_platform: params[:streaming_platform],
+ subject_id: subject_id,
+ batch_id: batch_id,
+ )
+ unless @eduapp_user_session.save
+ render json: @eduapp_user_session.errors, status: :unprocessable_entity and return
+ end
+ end
+
+ render json: @eduapp_user_session
+ end
+ end
+
+ private
+
+ # Checks if ```Subject``` is present in the user's ```Course```.
+ def subject_in_user_course(s_id)
+ c_id = Subject.find(s_id).course_id
+ if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_eduapp_user_session
+ @eduapp_user_session = EduappUserSession.find(params[:id])
+ end
+
+ def set_new_session_days
+ days_added = 0
+ weeks_passed = 0
+ week_days_passed = 1
+ first_week = true
+
+ @new_session_days = []
+ cursor_date = params[:session_start_date].split("T")[0].to_date - 1
+ last_cursor_date = cursor_date
+
+ while days_added <= params[:diff_days]
+ if !first_week
+ if params[:week_repeat] > 0
+ if cursor_date.strftime("%U").to_i != last_cursor_date.strftime("%U").to_i
+ weeks_passed = 0 if weeks_passed >= params[:week_repeat]
+ weeks_passed += 1
+ if weeks_passed < params[:week_repeat]
+ cursor_date = cursor_date + 7
+ if cursor_date > params[:session_end_date].split("T")[0].to_date
+ break
+ end
+ next
+ end
+ end
+ end
+ end
+
+ if (params[:check_week_days][0] && cursor_date.monday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][1] && cursor_date.tuesday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][2] && cursor_date.wednesday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][3] && cursor_date.thursday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][4] && cursor_date.friday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][5] && cursor_date.saturday?)
+ @new_session_days.append(cursor_date)
+ end
+ if (params[:check_week_days][6] && cursor_date.sunday?)
+ @new_session_days.append(cursor_date)
+ end
+
+ days_added += 1
+ last_cursor_date = cursor_date
+ cursor_date = cursor_date + 1
+ week_days_passed += 1
+ if week_days_passed > 7
+ first_week = false
+ week_days_passed = 0
+ end
+ end
+ end
+
+ # Only allow a list of trusted parameters through.
+ def permitted_params
+ params.require(:eduapp_user_session)
+ .permit(
+ :session_name,
+ :session_start_date,
+ :session_end_date,
+ :streaming_platform,
+ :resources_platform,
+ :session_chat_id,
+ :subject_id,
+ :number_repeat,
+ :check_week_days,
+ :week_repeat,
+ :diff_days
+ )
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/institutions_controller.rb b/backend/eduapp_db/app/controllers/institutions_controller.rb
index 7d54b63a..a6978965 100644
--- a/backend/eduapp_db/app/controllers/institutions_controller.rb
+++ b/backend/eduapp_db/app/controllers/institutions_controller.rb
@@ -1,70 +1,70 @@
-class InstitutionsController < ApplicationController
- before_action :set_institution, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /institutions
- def index
- if !check_perms_all!(get_user_roles.perms_institution)
- return
- end
- @institutions = Institution.all
-
- if params[:page]
- @institutions = query_paginate(@institutions, params[:page])
- end
-
- render json: @institutions
- end
-
- # GET /institutions/1
- def show
- render json: @institution
- end
-
- # POST /institutions
- def create
- if !check_perms_query!(get_user_roles.perms_institution)
- return
- end
- @institution = Institution.new(institution_params)
-
- if @institution.save
- render json: @institution, status: :created, location: @institution
- else
- render json: @institution.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /institutions/1
- def update
- if !check_perms_update!(get_user_roles.perms_institution, false, :null)
- return
- end
- if @institution.update(institution_params)
- render json: @institution
- else
- render json: @institution.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /institutions/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_institution, false, :null)
- return
- end
- @institution.destroy
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_institution
- @institution = Institution.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def institution_params
- params.permit(:name)
- end
-end
+class InstitutionsController < ApplicationController
+ before_action :set_institution, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /institutions
+ def index
+ if !check_perms_all!(get_user_roles.perms_institution)
+ return
+ end
+ @institutions = Institution.all
+
+ if params[:page]
+ @institutions = query_paginate(@institutions, params[:page])
+ end
+
+ render json: @institutions
+ end
+
+ # GET /institutions/1
+ def show
+ render json: @institution
+ end
+
+ # POST /institutions
+ def create
+ if !check_perms_query!(get_user_roles.perms_institution)
+ return
+ end
+ @institution = Institution.new(institution_params)
+
+ if @institution.save
+ render json: @institution, status: :created, location: @institution
+ else
+ render json: @institution.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /institutions/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_institution, false, :null)
+ return
+ end
+ if @institution.update(institution_params)
+ render json: @institution
+ else
+ render json: @institution.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /institutions/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_institution, false, :null)
+ return
+ end
+ @institution.destroy
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_institution
+ @institution = Institution.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def institution_params
+ params.permit(:name)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/push_notifications_controller.rb b/backend/eduapp_db/app/controllers/push_notifications_controller.rb
new file mode 100644
index 00000000..9d0d26f8
--- /dev/null
+++ b/backend/eduapp_db/app/controllers/push_notifications_controller.rb
@@ -0,0 +1,50 @@
+class PushNotificationsController < ApplicationController
+ before_action :authenticate_user!, except: [:key, :subscribe]
+ before_action :check_role!, except: [:key, :subscribe]
+
+ def key
+ render json: { public_key: Base64.urlsafe_decode64(ENV.fetch("VAPID_PUBLIC_KEY")).bytes }
+ end
+
+ def subscribe
+ push_notification = PushNotification.find_by(auth: permit_params[:auth])
+ if !push_notification
+ push_notification = PushNotification.new(permit_params)
+ end
+
+ if push_notification.save
+ render json: push_notification, status: :created
+ else
+ render json: push_notification.errors, status: :unprocessable_entity
+ end
+ end
+
+ # def push
+ # push_notifications = PushNotification.where(user_id: @current_user)
+ # message = {
+ # title: "title",
+ # body: "body",
+ # icon: "http://example.com/icon.pn"
+ # }
+ # push_notifications.each do |push_noficification|
+ # Webpush.payload_send(
+ # endpoint: push_noficification.endpoint,
+ # message: JSON.generate(message),
+ # p256dh: push_noficification.p256dh,
+ # auth: push_noficification.auth,
+ # vapid: {
+ # subject: "mailto:alejandro.vera1988@example.com",
+ # public_key: ENV.fetch('VAPID_PUBLIC_KEY'),
+ # private_key: ENV.fetch('VAPID_PRIVATE_KEY')
+ # }
+ # )
+ # end
+ # end
+
+ private
+
+ def permit_params
+ params.permit(:endpoint, :user_id, :p256dh, :auth)
+ end
+
+end
diff --git a/backend/eduapp_db/app/controllers/resources_controller.rb b/backend/eduapp_db/app/controllers/resources_controller.rb
index acafb254..00cbdfd8 100644
--- a/backend/eduapp_db/app/controllers/resources_controller.rb
+++ b/backend/eduapp_db/app/controllers/resources_controller.rb
@@ -1,216 +1,213 @@
-class ResourcesController < ApplicationController
- before_action :set_resource, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /resources
- def index
- if params[:subject_id]
- if !subject_in_user_course(params[:subject_id])
- return deny_perms_access!
- end
- @resources = Resource.order(created_at: :desc).where(subject_id: params[:subject_id])
- else
- if !check_perms_all!(get_user_roles.perms_resources)
- return
- end
- @resources = Resource.all
- end
-
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @resources = @resources.order(parse_filter_order(params[:order]))
- else
- @resources = @resources.order(name: :asc)
- end
-
- if params[:page]
- @resources = query_paginate(@resources, params[:page])
- @resources[:current_page] = serialize_each(@resources[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:user, :subject])
- end
-
- render json: @resources
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- resources_query = {}
- subject_query = {}
- params.each do |param|
- next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "resource"
- next unless param[1] != "null" && param[1].length > 0
-
- query = { param[0] => param[1] }
- case param[0]
- when "id", "name", "author"
- resources_query.merge!(query)
- when "subject_name"
- subject_query.merge!(query)
- end
- end
-
- final_query = params[:extras] ? filter_extrafields(params[:extras], Resource) : nil
-
- if !resources_query.empty?
- query = !final_query.nil? ? final_query : nil
-
- if resources_query["id"]
- ids = []
- Resource.all.each do |r|
- ids << r.id if r.id.to_s =~ /^#{resources_query["id"]}.*$/
- end
- query = Resource.where(id: ids)
- end
-
- if resources_query["name"]
- if !query.nil?
- query = query.where("name LIKE ?", "%#{resources_query["name"]}%")
- else
- query = Resource.where("name LIKE ?", "%#{resources_query["name"]}%")
- end
- end
-
- if resources_query["author"]
- if !query.nil?
- query = query.where(user_id: User.where("email LIKE ?", "%#{resources_query["author"]}%"))
- else
- query = Resource.where(user_id: User.where("email LIKE ?", "%#{resources_query["author"]}%"))
- end
- end
-
- final_query = query
- end
-
- if !final_query.nil? && !subject_query.empty?
- final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- elsif !subject_query.empty?
- final_query = Resource.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:user, :subject])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /resources/1
- def show
- if !resource_in_user_course && get_user_roles.name != get_admin_role.name
- return deny_perms_access!
- end
- render json: @resource
- end
-
- # POST /resources
- def create
- if !check_perms_write!(get_user_roles.perms_resources)
- return
- end
- @resource = Resource.new(
- name: params[:name],
- description: params[:description],
- user_id: params[:user_id],
- subject_id: params[:subject_id],
- )
-
- if @resource.save
- files = []
- x = 0
- while x < 9
- files.append(resource_params["file_#{x}"]) if !resource_params["file_#{x}"].nil?
- x += 1
- end
-
- if files.count > 0
- @resource.files.attach(files)
- if @resource.files.attached?
- sFiles = []
- json = []
- for f in @resource.files.attachments
- sFiles.append(url_for(f))
- json.append(f.to_json)
- end
- @resource.resource_files = sFiles
- @resource.resource_files_json = json
- if @resource.save
- render json: @resource, status: :created, location: @resource and return
- else
- render json: @resource.errors, status: :unprocessable_entity and return
- end
- end
- end
- render json: @resource, status: :created, location: @resource
- else
- render json: @resource.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /resources/1
- def update
- if !check_perms_update!(get_user_roles.perms_resources, true, @resource.user_id)
- return
- end
-
- if @resource.update(name: params[:name], description: params[:description], resource_files: params[:resource_files], resource_files_json: params[:resource_files_json], blob_id_delete: params[:blob_id_delete], subject_id: params[:subject_id])
- for idDelete in params[:blob_id_delete]
- @resource.files.find(idDelete).purge
- end
- render json: @resource
- else
- render json: @resource.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /resources/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_resources, true, @resource.user_id)
- return
- end
- if @resource.files.attached?
- @resource.files.attachments.each do |attachment|
- attachment.purge
- end
- end
- @resource.destroy
- end
-
- private
-
- # Only allow a list of trusted parameters through.
- def resource_params
- permits = [:id, :name, :description, :blob_id_delete, :user_id, :subject_id]
-
- x = 0
- while x < 10
- permits.append("file_#{x}")
- x += 1
- end
- params.permit(permits)
- end
-
- # Checks if ```Subject``` is present in the user's ```Course```.
- def subject_in_user_course(s_id)
- c_id = Subject.find(s_id).course_id
- if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
- return true
- end
- return false
- end
-
- # Checks if ```Resource``` is present in the user's ```Course```.
- def resource_in_user_course
- c_id = Subject.find(@resource.subject_id).course_id
- if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_resource
- @resource = Resource.find(params[:id])
- end
-end
+class ResourcesController < ApplicationController
+ before_action :set_resource, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /resources
+ def index
+ if params[:subject_id]
+ @resources = Resource.order(created_at: :desc).where(subject_id: params[:subject_id])
+ else
+ if !check_perms_all!(get_user_roles.perms_resources)
+ return
+ end
+ @resources = Resource.all
+ end
+
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ @resources = @resources.order(parse_filter_order(params[:order]))
+ else
+ @resources = @resources.order(name: :asc)
+ end
+
+ if params[:page]
+ @resources = query_paginate(@resources, params[:page])
+ @resources[:current_page] = serialize_each(@resources[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:user, :subject])
+ end
+
+ render json: @resources
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ resources_query = {}
+ subject_query = {}
+ params.each do |param|
+ next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "resource"
+ next unless param[1] != "null" && param[1].length > 0
+
+ query = { param[0] => param[1] }
+ case param[0]
+ when "id", "name", "author"
+ resources_query.merge!(query)
+ when "subject_name"
+ subject_query.merge!(query)
+ end
+ end
+
+ final_query = params[:extras] ? filter_extrafields(params[:extras], Resource) : nil
+
+ if !resources_query.empty?
+ query = !final_query.nil? ? final_query : nil
+
+ if resources_query["id"]
+ ids = []
+ Resource.all.each do |r|
+ ids << r.id if r.id.to_s =~ /^#{resources_query["id"]}.*$/
+ end
+ query = Resource.where(id: ids)
+ end
+
+ if resources_query["name"]
+ if !query.nil?
+ query = query.where("name LIKE ?", "%#{resources_query["name"]}%")
+ else
+ query = Resource.where("name LIKE ?", "%#{resources_query["name"]}%")
+ end
+ end
+
+ if resources_query["author"]
+ if !query.nil?
+ query = query.where(user_id: User.where("email LIKE ?", "%#{resources_query["author"]}%"))
+ else
+ query = Resource.where(user_id: User.where("email LIKE ?", "%#{resources_query["author"]}%"))
+ end
+ end
+
+ final_query = query
+ end
+
+ if !final_query.nil? && !subject_query.empty?
+ final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ elsif !subject_query.empty?
+ final_query = Resource.where(subject_id: Subject.where("name LIKE ?", "%#{subject_query["subject_name"]}%"))
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :subject_id], [:user, :subject])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /resources/1
+ def show
+ if !resource_in_user_course && get_user_roles.name != get_admin_role.name
+ return deny_perms_access!
+ end
+ render json: @resource
+ end
+
+ # POST /resources
+ def create
+ if !check_perms_write!(get_user_roles.perms_resources)
+ return
+ end
+ @resource = Resource.new(
+ name: params[:name],
+ description: params[:description],
+ user_id: params[:user_id],
+ subject_id: params[:subject_id],
+ )
+
+ if @resource.save
+ files = []
+ x = 0
+ while x < 9
+ files.append(resource_params["file_#{x}"]) if !resource_params["file_#{x}"].nil?
+ x += 1
+ end
+
+ if files.count > 0
+ @resource.files.attach(files)
+ if @resource.files.attached?
+ sFiles = []
+ json = []
+ for f in @resource.files.attachments
+ sFiles.append(url_for(f))
+ json.append(f.to_json)
+ end
+ @resource.resource_files = sFiles
+ @resource.resource_files_json = json
+ if @resource.save
+ render json: @resource, status: :created, location: @resource and return
+ else
+ render json: @resource.errors, status: :unprocessable_entity and return
+ end
+ end
+ end
+ render json: @resource, status: :created, location: @resource
+ else
+ render json: @resource.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /resources/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_resources, true, @resource.user_id)
+ return
+ end
+
+ if @resource.update(name: params[:name], description: params[:description], resource_files: params[:resource_files], resource_files_json: params[:resource_files_json], blob_id_delete: params[:blob_id_delete], subject_id: params[:subject_id])
+ for idDelete in params[:blob_id_delete]
+ @resource.files.find(idDelete).purge
+ end
+ render json: @resource
+ else
+ render json: @resource.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /resources/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_resources, true, @resource.user_id)
+ return
+ end
+ if @resource.files.attached?
+ @resource.files.attachments.each do |attachment|
+ attachment.purge
+ end
+ end
+ @resource.destroy
+ end
+
+ private
+
+ # Only allow a list of trusted parameters through.
+ def resource_params
+ permits = [:id, :name, :description, :blob_id_delete, :user_id, :subject_id]
+
+ x = 0
+ while x < 10
+ permits.append("file_#{x}")
+ x += 1
+ end
+ params.permit(permits)
+ end
+
+ # Checks if ```Subject``` is present in the user's ```Course```.
+ def subject_in_user_course(s_id)
+ c_id = Subject.find(s_id).course_id
+ if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
+ return true
+ end
+ return false
+ end
+
+ # Checks if ```Resource``` is present in the user's ```Course```.
+ def resource_in_user_course
+ c_id = Subject.find(@resource.subject_id).course_id
+ if Tuition.where(user_id: @current_user, course_id: c_id).count > 0
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_resource
+ @resource = Resource.find(params[:id])
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/subjects_controller.rb b/backend/eduapp_db/app/controllers/subjects_controller.rb
index d29b29a6..6e77158e 100644
--- a/backend/eduapp_db/app/controllers/subjects_controller.rb
+++ b/backend/eduapp_db/app/controllers/subjects_controller.rb
@@ -1,212 +1,254 @@
-class SubjectsController < ApplicationController
- before_action :set_subject, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /subjects
- def index
- wants_info_for_calendar = false
-
- if params[:user_id]
- wants_info_for_calendar = true
- if !check_perms_query_self!(get_user_roles.perms_subjects, params[:user_id])
- return
- end
- # TODO: Possible refactorization:
- # tuitions = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
- # @Subjects = Subject.where(course_id: tuitions)
- # @todaySessions = EduappUserSession.where(subject_id: @Subjects).pluck(:session_start_date)
- # @Sessions = []
-
- # for hour in @todaySessions
- # if (hour.split("T")[1].split(":")[0] == @TodayHourNow or hour.split("T")[1].split(":")[0] >= @TodayHourNow and hour.split("T")[0] == @Today)
- # @Sessions += EduappUserSession.where(subject_id: @Subjects, session_start_date: hour)
- # end
- # end
- # @subjects = @Sessions
-
- @Subjects = []
- @Sessions = []
- @Today = Time.now.strftime("%F")
- @TodayHourNow = Time.now.strftime("%H")
- @todaySessions = []
-
- @TuitionsUserId = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
-
- for course in @TuitionsUserId
- @Subjects += Subject.where(course_id: course)
- end
-
- for subject in @Subjects
- @todaySessions += EduappUserSession.where(subject_id: subject).pluck(:session_start_date)
- end
-
- for hour in @todaySessions
- if (hour.split("T")[1].split(":")[0] == @TodayHourNow or hour.split("T")[1].split(":")[0] >= @TodayHourNow and hour.split("T")[0] == @Today)
- @Sessions += EduappUserSession.where(subject_id: @Subjects, session_start_date: hour)
- else
- end
- end
-
- @subjects = @Sessions
- elsif params[:name]
- # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
- @subjects = Subject.where(name: params[:name])
- elsif params[:user]
- # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
- @subjects = Subject.where(course_id: Tuition.where(user_id: params[:user]).pluck(:course_id))
- else
- if !check_perms_all!(get_user_roles.perms_subjects)
- return
- end
- @subjects = Subject.all
- end
-
- if !wants_info_for_calendar
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @subjects = @subjects.order(parse_filter_order(params[:order]))
- else
- @subjects = @subjects.order(name: :asc)
- end
- end
-
- if params[:page]
- @subjects = query_paginate(@subjects, params[:page])
- @subjects[:current_page] = serialize_each(@subjects[:current_page], [:created_at, :updated_at, :course], [:course])
- end
-
- render json: @subjects
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- subjects_query = {}
- course_query = {}
- params.each do |param|
- next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "subject"
- next unless param[1] != "null" && param[1].length > 0
-
- query = { param[0] => param[1] }
- case param[0]
- when "id", "name", "subject_code"
- subjects_query.merge!(query)
- when "course_name"
- course_query.merge!(query)
- end
- end
-
- final_query = params[:extras] ? filter_extrafields(params[:extras], Subject) : nil
-
- if !subjects_query.empty?
- query = !final_query.nil? ? final_query : nil
-
- if subjects_query["id"]
- ids = []
- Subject.all.each do |s|
- ids << s.id if s.id.to_s =~ /^#{subjects_query["id"]}.*$/
- end
- query = Subject.where(id: ids)
- end
-
- if subjects_query["name"]
- if !query.nil?
- query = query.where("name LIKE ?", "%#{subjects_query["name"]}%")
- else
- query = Subject.where("name LIKE ?", "%#{subjects_query["name"]}%")
- end
- end
-
- if subjects_query["subject_code"]
- if !query.nil?
- query = query.where("subject_code LIKE ?", "%#{subjects_query["subject_code"]}%")
- else
- query = Subject.where("subject_code LIKE ?", "%#{subjects_query["subject_code"]}%")
- end
- end
-
- final_query = query
- end
-
- if !final_query.nil? && !course_query.empty?
- final_query = final_query.where(course_id: Course.where("name LIKE ?", "%#{course_query["course_name"]}%"))
- elsif !course_query.empty?
- final_query = Subject.where(course_id: Course.where("name LIKE ?", "%#{course_query["course_name"]}%"))
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :course_id], [:course])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /subjects/1
- def show
- if !check_perms_query!(get_user_roles.perms_subjects) && !subject_in_user_course
- return
- end
- render json: @subject
- end
-
- # POST /subjects
- def create
- if !check_perms_write!(get_user_roles.perms_subjects)
- return
- end
-
- if Subject.where(subject_code: params[:subject_code]).count > 0
- render json: @Subject, status: :unprocessable_entity
- else
- puts "Creating subject: "
- @subject = Subject.new(subject_code: params[:subject_code], name: params[:name], description: params[:description], color: params[:color], course_id: params[:course_id])
- if @subject.save
- render json: @subject, status: :created, location: @subject
- else
- render json: @subject.errors, status: :unprocessable_entity
- end
- end
- end
-
- # PUT /subjects/1
- def update
- if !check_perms_update!(get_user_roles.perms_subjects, false, :null)
- return
- end
- if @subject.update(subject_params)
- render json: @subject
- else
- render json: @subject.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /subjects/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_subjects, false, :null)
- return
- end
- @subject.destroy
- end
-
- private
-
- # Checks if ```Subject``` is present in the user's ```Course```.
- def subject_in_user_course
- if Tuition.where(user_id: @current_user, course_id: @subject.course_id).count > 0
- return true
- end
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_subject
- @subject = Subject.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def subject_params
- params.require(:subject).permit(:subject_code, :name, :description, :color, :course_id)
- end
-end
+class SubjectsController < ApplicationController
+ before_action :set_subject, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /subjects
+ def index
+ wants_info_for_calendar = false || params[:wants_info_for_calendar]
+
+ if params[:user_id]
+ wants_info_for_calendar = true
+ if !check_perms_query_self!(get_user_roles.perms_subjects, params[:user_id])
+ return
+ end
+ # TODO: Possible refactorization:
+ # tuitions = Tuition.where(user_id: params[:user_id]).pluck(:course_id)
+ # @Subjects = Subject.where(course_id: tuitions)
+ # @todaySessions = EduappUserSession.where(subject_id: @Subjects).pluck(:session_start_date)
+ # @Sessions = []
+
+ # for hour in @todaySessions
+ # if (hour.split("T")[1].split(":")[0] == @TodayHourNow or hour.split("T")[1].split(":")[0] >= @TodayHourNow and hour.split("T")[0] == @Today)
+ # @Sessions += EduappUserSession.where(subject_id: @Subjects, session_start_date: hour)
+ # end
+ # end
+ # @subjects = @Sessions
+
+ @subjects = User.find(params[:user_id]).subjects
+ elsif params[:all_sessions]
+ #TODO: cambiar esta lógica pasarla a eventos, calendario(analizar)
+ # Tiene que devolver todos los evenos que hay hoy, sin tener que preguntar por la hora
+ @sessions = []
+ @today = Time.now.strftime("%F")
+ @todayHourNow = Time.now.strftime("%H")
+ user = User.find(current_user)
+ if user.user_info.user_role.name == 'eduapp-teacher'
+ @user_subjects = user.user_info.teaching_list
+ else
+ @user_subjects = user.subjects.pluck(:id)
+ end
+ @todaySessions = []
+ for subject in @user_subjects
+ @todaySessions += EduappUserSession.where(subject_id: subject).pluck(:session_start_date)
+ end
+
+ for hour in @todaySessions
+ if (hour.split("T")[1].split(":")[0] == @todayHourNow or hour.split("T")[1].split(":")[0] >= @todayHourNow and hour.split("T")[0] == @today)
+ @sessions += EduappUserSession.where(subject_id: @user_subjects, session_start_date: hour)
+ end
+ end
+ @subjects = @sessions
+ elsif params[:subject_id]
+ @subjects = Subject.where(id: params[:subject_id])
+ elsif params[:name]
+ # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
+ @subjects = Subject.where('name ilike ?', "%#{params[:name]}%")
+ elsif params[:subject_code]
+ # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
+ @subjects = Subject.where('subject_code ilike ?', "%#{params[:subject_code]}%")
+ elsif params[:id]
+ # TODO: HANDLE PERMISSIONS FOR NAME QUERIES
+ @subjects = Subject.where('id::text ilike ?', "%#{params[:id]}%")
+ elsif params[:user]
+ # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
+ @subjects = Subject.where(course_id: Tuition.where(user_id: params[:user]).pluck(:course_id))
+ elsif params[:course_name]
+ # TODO: HANDLE PERMISSIONS FOR CHAINED SUBJECT QUERIES
+ @subjects = Subject.joins(:course).where('courses.name ilike ?', "%#{params[:course_name]}%")
+ else
+ if !check_perms_all!(get_user_roles.perms_subjects)
+ return
+ end
+ @subjects = Subject.all
+ end
+
+ if wants_info_for_calendar
+ order = !params[:order].nil? && JSON.parse(Base64.decode64(params[:order]))
+ if order && order["field"] != ""
+ if order["field"] == 'course_name'
+ @subjects = @subjects.joins(:course)
+ end
+ @subjects = @subjects.order(parse_filter_order(order,{'course_name' => 'courses.name'}))
+ else
+ @subjects = @subjects.order(name: :asc)
+ end
+ end
+
+ if params[:page]
+ @subjects = query_paginate(@subjects, params[:page])
+ @subjects[:current_page] = serialize_each(@subjects[:current_page], [:created_at, :updated_at], [:course, :users])
+ end
+
+ render json: @subjects
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ subjects_query = {}
+ course_query = {}
+ params.each do |param|
+ next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "subject"
+ next unless param[1] != "null" && param[1].length > 0
+
+ query = { param[0] => param[1] }
+ case param[0]
+ when "id", "name", "subject_code"
+ subjects_query.merge!(query)
+ when "course_name"
+ course_query.merge!(query)
+ end
+ end
+
+ final_query = params[:extras] ? filter_extrafields(params[:extras], Subject) : nil
+
+ if !subjects_query.empty?
+ query = !final_query.nil? ? final_query : nil
+
+ if subjects_query["id"]
+ ids = []
+ Subject.all.each do |s|
+ ids << s.id if s.id.to_s =~ /^#{subjects_query["id"]}.*$/
+ end
+ query = Subject.where(id: ids)
+ end
+
+ if subjects_query["name"]
+ if !query.nil?
+ query = query.where("name LIKE ?", "%#{subjects_query["name"]}%")
+ else
+ query = Subject.where("name LIKE ?", "%#{subjects_query["name"]}%")
+ end
+ end
+
+ if subjects_query["subject_code"]
+ if !query.nil?
+ query = query.where("subject_code LIKE ?", "%#{subjects_query["subject_code"]}%")
+ else
+ query = Subject.where("subject_code LIKE ?", "%#{subjects_query["subject_code"]}%")
+ end
+ end
+
+ final_query = query
+ end
+
+ if !final_query.nil? && !course_query.empty?
+ final_query = final_query.where(course_id: Course.where("name LIKE ?", "%#{course_query["course_name"]}%"))
+ elsif !course_query.empty?
+ final_query = Subject.where(course_id: Course.where("name LIKE ?", "%#{course_query["course_name"]}%"))
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :course_id], [:course])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /subjects/1
+ #TODO: probar pasar un parametro render(boolean) para controlar los render anidados
+ def show
+ if !check_perms_query!(get_user_roles.perms_subjects, false) && !check_perms_query_self!(get_user_roles.perms_subjects, current_user)
+ deny_perms_access!
+ return
+ end
+ render json: @subject
+ end
+
+ # POST /subjects
+ def create
+ if !check_perms_write!(get_user_roles.perms_subjects)
+ return
+ end
+
+ if Subject.where(subject_code: params[:subject_code]).count > 0
+ render json: @Subject, status: :unprocessable_entity
+ elsif params[:enrollment] # TODO: refactor crear una acción
+ @subject = Subject.find(params[:subject_id])
+ @subject.users << User.find(params[:user_id])
+ @subject.save
+ else
+ @subject = Subject.new(subject_code: params[:subject_code],
+ external_id: params[:external_id], name: params[:name],
+ description: params[:description], color: params[:color],
+ course_id: params[:course_id], chat_link: params[:chat_link])
+ if @subject.save
+ render json: @subject, status: :created, location: @subject
+ else
+ render json: @subject.errors, status: :unprocessable_entity
+ end
+ end
+ end
+
+ # PUT /subjects/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_subjects, true, current_user, false)
+ return
+ end
+ if @subject.update(subject_params)
+ render json: @subject
+ else
+ render json: @subject.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /subjects/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_subjects, false, :null)
+ return
+ end
+ @subject.destroy
+ end
+
+ # DELETE /subjects/1/users/1
+ def destroy_user
+ if !check_perms_delete!(get_user_roles.perms_subjects, false, :null)
+ return
+ end
+ @subject = Subject.find(params[:subject_id])
+ @subject.users.destroy(params[:user_id])
+ end
+
+ private
+
+ # Checks if ```Subject``` is present in the user's ```Course```.
+ def subject_in_user_course
+ if Tuition.where(user_id: @current_user, course_id: @subject.course_id).count > 0
+ return true
+ end
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_subject
+ @subject = Subject.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def subject_params
+ params.require(:subject)
+ .permit(
+ :id,
+ :subject_code,
+ :external_id,
+ :name,
+ :description,
+ :color,
+ :chat_link,
+ :course_id
+ )
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/subjects_users_controller.rb b/backend/eduapp_db/app/controllers/subjects_users_controller.rb
new file mode 100644
index 00000000..30894607
--- /dev/null
+++ b/backend/eduapp_db/app/controllers/subjects_users_controller.rb
@@ -0,0 +1,126 @@
+class SubjectsUsersController < ApplicationController
+ before_action :set_subject_user, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ def index
+ if !check_perms_all!(get_user_roles.perms_tuitions)
+ return
+ end
+ enroll_query = {}
+ params.each do |param|
+ next unless param[0] == "user_email" || param[0] == "subject_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ enroll_query.merge!({ param[0] => param[1] })
+ end
+
+ @subjects_users = SubjectsUser
+
+ if params[:user_id]
+ @subjects_users = SubjectsUser.where(user_id: params[:user_id])
+ end
+
+ if enroll_query["user_email"]
+ @subjects_users = SubjectsUser.where(user_id: User.where("email LIKE ?", "%#{enroll_query["user_email"]}%"))
+ end
+
+ if enroll_query["subject_name"]
+ @subjects_users = SubjectsUser.where(subject_id: Subject.where("name LIKE ?", "%#{enroll_query["subject_name"]}%"))
+ end
+
+ if params[:page]
+ @subjects_users = query_paginate(@subjects_users, params[:page] || 1)
+ @subjects_users[:current_page] = serialize_each(@subjects_users[:current_page], [:created_at, :updated_at, :subject, :user_id], [:subject, :user])
+ end
+
+ render json: @subjects_users
+ end
+
+ def filter
+ enroll_query = {}
+ params.each do |param|
+ next unless param[0] == "user_email" || param[0] == "subject_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ enroll_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = nil
+
+ if enroll_query["user_email"]
+ final_query = SubjectsUser.where(user_id: User.where("email LIKE ?", "%#{enroll_query["user_email"]}%"))
+ end
+
+ if enroll_query["subject_name"]
+ if !final_query.nil?
+ final_query = final_query.where(subject_id: Subject.where("name LIKE ?", "%#{enroll_query["subject_name"]}%"))
+ else
+ final_query = SubjectsUser.where(subject_id: Subject.where("name LIKE ?", "%#{enroll_query["subject_name"]}%"))
+ end
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :course_id], [:user, :course])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ def show
+ if !check_perms_query!(get_user_roles.perms_tuitions)
+ return
+ end
+ render json: @subject_user
+ end
+
+ def create
+ if !check_perms_write!(get_user_roles.perms_tuitions)
+ return
+ end
+
+ @subject_user = SubjectsUser.new(subject_id: params[:subject_id], user_id: params[:user_id])
+ if SubjectsUser.where(user_id: params[:user_id], subject_id: params[:subject_id]).count > 0
+ render json: @subject_user.errors, status: :unprocessable_entity
+ else
+ if @subject_user.save
+ render json: @subject_user, status: :created, location: @subject_user
+ else
+ render json: @subject_user.errors, status: :unprocessable_entity
+ end
+ end
+ end
+
+ def update
+ if !check_perms_update!(get_user_roles.perms_tuitions, false, :null)
+ return
+ end
+
+ if @subject_user.update(subject_id: params[:subject_id], user_id: params[:user_id], id: params[:id])
+ render json: @subject_user
+ else
+ render json: @subject_user.errors, status: :unprocessable_entity
+ end
+ end
+
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_tuitions, false, :null)
+ return
+ end
+
+ @subject_user.destroy
+ end
+
+ private
+
+ def set_subject_user
+ @subject_user = SubjectsUser.find(params[:id])
+ end
+
+ def subject_user_params
+ params.require(:subject_user).permit(:subject_id, :user_id, :id)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/tuitions_controller.rb b/backend/eduapp_db/app/controllers/tuitions_controller.rb
index 80d3629d..cd38224f 100644
--- a/backend/eduapp_db/app/controllers/tuitions_controller.rb
+++ b/backend/eduapp_db/app/controllers/tuitions_controller.rb
@@ -1,114 +1,128 @@
-class TuitionsController < ApplicationController
- before_action :set_tuition, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /tuitions
- def index
- if !check_perms_all!(get_user_roles.perms_tuitions)
- return
- end
- @tuitions = Tuition.all
-
- if params[:page]
- @tuitions = query_paginate(@tuitions, params[:page])
- @tuitions[:current_page] = serialize_each(@tuitions[:current_page], [:created_at, :updated_at, :course, :user_id], [:course, :user])
- end
-
- render json: @tuitions
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- enroll_query = {}
- params.each do |param|
- next unless param[0] == "user_email" || param[0] == "course_name"
- next unless param[1] != "null" && param[1].length > 0
-
- enroll_query.merge!({ param[0] => param[1] })
- end
-
- final_query = nil
-
- if enroll_query["user_email"]
- final_query = Tuition.where(user_id: User.where("email LIKE ?", "%#{enroll_query["user_email"]}%"))
- end
-
- if enroll_query["course_name"]
- if !final_query.nil?
- final_query = final_query.where(course_id: Course.where("name LIKE ?", "%#{enroll_query["course_name"]}%"))
- else
- final_query = Tuition.where(course_id: Course.where("name LIKE ?", "%#{enroll_query["course_name"]}%"))
- end
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :course_id], [:user, :course])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /tuitions/1
- def show
- if !check_perms_query!(get_user_roles.perms_tuitions)
- return
- end
- render json: @tuition
- end
-
- # POST /tuitions
- def create
- if !check_perms_write!(get_user_roles.perms_tuitions)
- return
- end
-
- @tuition = Tuition.new(course_id: params[:course_id], user_id: params[:user_id])
- if Tuition.where(user_id: params[:user_id], course_id: params[:course_id]).count > 0
- render json: @tuition.errors, status: :unprocessable_entity
- else
- if @tuition.save
- render json: @tuition, status: :created, location: @tuition
- else
- render json: @tuition.errors, status: :unprocessable_entity
- end
- end
- end
-
- # PATCH/PUT /tuitions/1
- def update
- if !check_perms_update!(get_user_roles.perms_tuitions, false, :null)
- return
- end
-
- if @tuition.update(course_id: params[:course_id], user_id: params[:user_id], id: params[:id])
- render json: @tuition
- else
- render json: @tuition.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /tuitions/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_tuitions, false, :null)
- return
- end
-
- @tuition.destroy
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_tuition
- @tuition = Tuition.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def tuition_params
- params.require(:tuition).permit(:course_id, :user_id, :id)
- end
-end
+class TuitionsController < ApplicationController
+ before_action :set_tuition, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /tuitions
+ def index
+ if !check_perms_all!(get_user_roles.perms_tuitions)
+ return
+ end
+ enroll_query = {}
+ params.each do |param|
+ next unless param[0] == "user_email" || param[0] == "course_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ enroll_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = Tuition
+
+ if enroll_query["user_email"]
+ final_query = final_query.where(user_id: User.where("email LIKE ?", "%#{enroll_query["user_email"]}%"))
+ end
+
+ if enroll_query["course_name"]
+ final_query = final_query.where(course_id: Course.where("name LIKE ?", "%#{enroll_query["course_name"]}%"))
+ end
+
+ @tuitions = query_paginate(final_query, params[:page] || 1)
+ @tuitions[:current_page] = serialize_each(@tuitions[:current_page], [:created_at, :updated_at, :course, :user_id], [:course, :user])
+
+ render json: @tuitions
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ enroll_query = {}
+ params.each do |param|
+ next unless param[0] == "user_email" || param[0] == "course_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ enroll_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = nil
+
+ if enroll_query["user_email"]
+ final_query = Tuition.where(user_id: User.where("email LIKE ?", "%#{enroll_query["user_email"]}%"))
+ end
+
+ if enroll_query["course_name"]
+ if !final_query.nil?
+ final_query = final_query.where(course_id: Course.where("name LIKE ?", "%#{enroll_query["course_name"]}%"))
+ else
+ final_query = Tuition.where(course_id: Course.where("name LIKE ?", "%#{enroll_query["course_name"]}%"))
+ end
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :course_id], [:user, :course])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /tuitions/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_tuitions)
+ return
+ end
+ render json: @tuition
+ end
+
+ # POST /tuitions
+ def create
+ if !check_perms_write!(get_user_roles.perms_tuitions)
+ return
+ end
+
+ @tuition = Tuition.new(course_id: params[:course_id], user_id: params[:user_id])
+ if Tuition.where(user_id: params[:user_id], course_id: params[:course_id]).count > 0
+ render json: @tuition.errors, status: :unprocessable_entity
+ else
+ if @tuition.save
+ render json: @tuition, status: :created, location: @tuition
+ else
+ render json: @tuition.errors, status: :unprocessable_entity
+ end
+ end
+ end
+
+ # PATCH/PUT /tuitions/1
+ def update
+ if !check_perms_update!(get_user_roles.perms_tuitions, false, :null)
+ return
+ end
+
+ if @tuition.update(course_id: params[:course_id], user_id: params[:user_id], id: params[:id])
+ render json: @tuition
+ else
+ render json: @tuition.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /tuitions/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_tuitions, false, :null)
+ return
+ end
+
+ @tuition.destroy
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_tuition
+ @tuition = Tuition.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def tuition_params
+ params.require(:tuition).permit(:course_id, :user_id, :id)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/user_infos_controller.rb b/backend/eduapp_db/app/controllers/user_infos_controller.rb
index 90cf3577..d8eca5df 100644
--- a/backend/eduapp_db/app/controllers/user_infos_controller.rb
+++ b/backend/eduapp_db/app/controllers/user_infos_controller.rb
@@ -1,310 +1,322 @@
-class UserInfosController < ApplicationController
- before_action :set_user_info, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /user_infos
- def index
- if params[:user_id]
- if !check_perms_query_self!(get_user_roles.perms_users, params[:user_id])
- return
- end
- @user_infos = UserInfo.where(user_id: params[:user_id])
- elsif params[:name]
- # TODO: CHECK IF USER CAN SEARCH BY NAME
- @user_infos = UserInfo.search_name(params[:name]).take(3)
- else
- if !check_perms_all!(get_user_roles.perms_users)
- return
- end
- @user_infos = UserInfo.all
- end
-
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @user_infos = @user_infos.order(parse_filter_order(params[:order]))
- else
- @user_infos = params[:name] ? @user_infos : @user_infos.order(user_name: :asc)
- end
-
- if params[:page]
- @user_infos = query_paginate(@user_infos, params[:page])
- @user_infos[:current_page] = serialize_each(@user_infos[:current_page], [:created_at, :googleid, :updated_at, :user_id, :user_role_id], [:user, :user_role])
- @user_infos[:current_page].each do |user_info|
- user_info["user"]["last_sign_in_at"] = User.find(user_info["user"]["id"]).last_sign_in_at
- end
- end
-
- render json: @user_infos
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- infos_query = {}
- user_query = {}
- role_query = {}
- params.each do |param|
- next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "user_info"
- next unless param[1] != "null" && param[1].length > 0
-
- query = { param[0] => param[1] }
- case param[0]
- when "user_id", "user_name"
- infos_query.merge!(query)
- when "email"
- user_query.merge!(query)
- when "role"
- role_query.merge!(query)
- end
- end
-
- extras = filter_extrafields(params[:extras], User)
- final_query = params[:extras] ? (!extras.nil? ? UserInfo.where(user_id: extras) : nil) : nil
-
- if !infos_query.empty?
- query = !final_query.nil? ? final_query : nil
-
- if infos_query["user_id"]
- user_ids = []
- UserInfo.all.each do |u|
- user_ids << u.user_id if u.user_id.to_s =~ /^#{infos_query["user_id"]}.*$/
- end
- query = !query.nil? ? final_query.where(user_id: user_ids) : UserInfo.where(user_id: user_ids)
- end
-
- if infos_query["user_name"]
- if !query.nil?
- query = query.where("user_name LIKE ?", "%#{infos_query["user_name"]}%")
- else
- query = UserInfo.where("user_name LIKE ?", "%#{infos_query["user_name"]}%")
- end
- end
-
- final_query = query
- end
-
- if !final_query.nil? && !user_query.empty?
- final_query = final_query.where(user_id: User.where("email LIKE ?", "%#{user_query["email"]}%"))
- elsif !user_query.empty?
- final_query = UserInfo.where(user_id: User.where("email LIKE ?", "%#{user_query["email"]}%"))
- end
-
- if !final_query.nil? && !role_query.empty?
- final_query = final_query.where(user_role_id: UserRole.where("name LIKE ?", "%#{role_query["role"]}%"))
- elsif !role_query.empty?
- final_query = UserInfo.where(user_role_id: UserRole.where("name LIKE ?", "%#{role_query["role"]}%"))
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page] && !final_query.instance_of?(Array)
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :user_role_id, :googleid], [:user, :user_role])
- end
-
- render json: { filtration: final_query }
- end
-
- # Returns a filtered query based on the parameters passed for teachers.
- def teacher_filter
- teacher_query = {}
- params.each do |param|
- next unless param[0] == "teacher_name" || param[0] == "subject_name"
- next unless param[1] != "null" && param[1].length > 0
-
- teacher_query.merge!({ param[0] => param[1] })
- end
-
- teachers = UserInfo.where(user_role_id: UserRole.where(name: ["eduapp-teacher", "eduapp-admin-query", "eduapp-admin"]))
- final_query = nil
- filtered_users = nil
- filtered_subjects = nil
-
- if teacher_query["teacher_name"]
- filtered_users = teachers.where("user_name LIKE ?", "%#{teacher_query["teacher_name"]}%")
- end
-
- if teacher_query["subject_name"]
- filtered_subjects = Subject.where("name LIKE ?", "%#{teacher_query["subject_name"]}%")
- end
-
- if !filtered_users.nil? || !filtered_subjects.nil?
- users = !filtered_users.nil? ? filtered_users : teachers
- subjects = !filtered_subjects.nil? ? filtered_subjects : Subject.all
-
- final_query = []
- users.each do |u|
- subjects.each do |s|
- next if final_query.include?({ user: u, subject: s })
- final_query << { user: u, subject: s } if u.teaching_list.include? s.id
- end
- end
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = array_paginate(final_query, params[:page])
- final_query.each do |t|
- t[:user] = UserInfo.find(t[:user][:id]).serializable_hash(except: [:created_at, :updated_at, :googleid, :calendar_event, :isLoggedWithGoogle, :profile_image, :user_role_id, :user_id], include: [:user])
- t[:subject] = Subject.find(t[:subject][:id]).serializable_hash(except: [:created_at, :updated_at, :course_id, :color, :description], include: [:course])
- end if !final_query.nil?
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /user_infos/1
- def show
- if !check_perms_query!(get_user_roles.perms_users)
- return
- end
- render json: @user_info
- end
-
- def system_user
- render json: UserInfo.where(user_name: "eduapp_system", user_role_id: get_admin_role.id).first, status: :ok and return
- end
-
- # POST /user_infos
- def create
- if !check_perms_write!(get_user_roles.perms_users)
- return
- end
- @user_info = UserInfo.new(user_info_params)
- if @user_info.save
- render json: @user_info, status: :created, location: @user_info
- else
- render json: @user_info.errors, status: :unprocessable_entity
- end
- end
-
- # Adds a ```Subject``` ID to the ```UserInfo``` ```:teaching_list``` array.
- def add_subject
- if !check_perms_write!(get_user_roles.perms_users)
- return
- end
- @user_info = UserInfo.where(user_id: params[:user_id]).first
- if @user_info.teaching_list.include?(params[:subject_id])
- render json: { message: "Subject already added" }, status: :unprocessable_entity and return
- end
- @user_info.teaching_list << Subject.find(params[:subject_id]).id
- @user_info.save
- render json: @user_info
- end
-
- # Adds a ```CalendarAnnotation``` ID to the ```UserInfo``` ```:calendar_event``` array.
- def add_events
- if !check_perms_write!(get_user_roles.perms_users)
- return
- end
- @user_info = UserInfo.all
- calendar_annotation = CalendarAnnotation.where(isPop: true)
-
- @user_info.each do |user_info|
- calendar_annotation.each do |annotation|
- if !user_info.calendar_event.include?(annotation.id.to_s)
- user_info.calendar_event << annotation.id
- end
- end
- user_info.save
- end
-
- render json: @user_info
- end
-
- # Removes a ```CalendarAnnotation``` ID of the ```UserInfo``` ```:calendar_event``` array.
- def remove_event
- if !check_perms_write!(get_user_roles.perms_users)
- return
- end
- @user_info = UserInfo.where(user_id: params[:user_id]).first
- @user_info.calendar_event.delete(CalendarAnnotation.find(params[:calendar_event]).id)
- @user_info.save
- render json: @user_info
- end
-
- # Removes a ```Subject``` ID of the ```UserInfo``` ```:teaching_list``` array.
- def remove_subject
- if !check_perms_write!(get_user_roles.perms_users)
- return
- end
- @user_info = UserInfo.where(user_id: params[:user_id]).first
- @user_info.teaching_list.delete(Subject.find(params[:subject_id]).id)
- @user_info.save
- render json: @user_info
- end
-
- # PUT /user_infos/1
- def update
- if !can_update_self(@user_info.user_id)
- if !check_perms_update!(get_user_roles.perms_users)
- return
- end
- end
-
- if @user_info.update(user_info_params)
- render json: @user_info
- else
- render json: @user_info.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /user_infos/1
- def destroy
- if !check_perms_delete!(get_user_roles.perms_users, true, UserInfo.find(params[:id]).user_id)
- return
- end
- @user_info.destroy
- end
-
- # Completely removes a ```User``` with it's respective
- # ```Tuition```, ```JtiMatchList``` and ```UserInfo``` linked entries.
- def destroyuser
- if !check_perms_delete!(get_user_roles.perms_users, true, params[:id])
- return
- end
- user = User.find(params[:id])
- user_i = UserInfo.find_by(user_id: params[:id])
-
- # Cannot delete a user if he's the last administrator.
- if UserInfo.where(user_role_id: get_admin_role.id).count === 1 && user_i.user_role_id === get_admin_role.id
- render json: { message: "Cannot delete the last admin." }, status: 403 and return
- end
-
- JtiMatchList.where(user_id: params[:id]).each do |jti|
- jti.destroy
- end
-
- Tuition.where(user_id: params[:id]).each do |tuition|
- tuition.destroy
- end
-
- if user_i.destroy
- if user.destroy
- render json: { message: "Deleted user successfully." }, status: :ok
- else
- render json: { message: "Couldn't delete user" }, status: 500
- end
- else
- render json: { message: "Couldn't delete user info" }, status: 500
- end
- end
-
- private
-
- # Tests if the requester id and the current ```User``` IDs are the same.
- def can_update_self(requester_id)
- return true if requester_id === @current_user
- return false
- end
-
- # Use callbacks to share common setup or constraints between actions.
- def set_user_info
- @user_info = UserInfo.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def user_info_params
- params.permit(:extras, :user_name, :user_id, :user_role, :calendar_event, :profile_image, :teaching_list, :googleid, :isLoggedWithGoogle)
- end
-end
+class UserInfosController < ApplicationController
+ before_action :set_user_info, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /user_infos
+ def index
+ @user_infos = UserInfo
+ if params[:user_id]
+ if !check_perms_query_self!(get_user_roles.perms_users, params[:user_id])
+ return
+ end
+ @user_infos = @user_infos.where(user_id: params[:user_id])
+ elsif params[:name]
+ # TODO: CHECK IF USER CAN SEARCH BY NAME
+ @user_infos = @user_infos.search_name(params[:name]).take(3)
+ elsif params[:user_name]
+ # TODO: CHECK IF USER CAN SEARCH BY USER NAME
+ @user_infos = @user_infos.search_name(params[:user_name]) #.take(3)
+ elsif params[:email]
+ # TODO: CHECK IF USER CAN SEARCH BY EMAIL
+ @user_infos = @user_infos.search_email(params[:email]) #.take(3)
+ else
+ if !check_perms_all!(get_user_roles.perms_users)
+ return
+ end
+ end
+
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ @user_infos = @user_infos.order(parse_filter_order(params[:order]))
+ else
+ @user_infos = params[:name] ? @user_infos : @user_infos.order(user_name: :asc)
+ end
+
+ if params[:extras]
+ extras = filter_extrafields(params[:extras], User)
+ @user_infos = @user_infos.where(user_id: extras)
+ end
+
+ if params[:page]
+ @user_infos = query_paginate(@user_infos, params[:page])
+ @user_infos[:current_page] = serialize_each(@user_infos[:current_page], [:created_at, :googleid, :updated_at, :user_id, :user_role_id], [:user, :user_role])
+ @user_infos[:current_page].each do |user_info|
+ user_info["user"]["last_sign_in_at"] = User.find(user_info["user"]["id"]).last_sign_in_at
+ end
+ end
+
+ render json: @user_infos
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ infos_query = {}
+ user_query = {}
+ role_query = {}
+ params.each do |param|
+ next if param[0] == "controller" || param[0] == "action" || param[0] == "extras" || param[0] == "user_info"
+ next unless param[1] != "null" && param[1].length > 0
+
+ query = { param[0] => param[1] }
+ case param[0]
+ when "user_id", "user_name"
+ infos_query.merge!(query)
+ when "email"
+ user_query.merge!(query)
+ when "role"
+ role_query.merge!(query)
+ end
+ end
+
+ extras = filter_extrafields(params[:extras], User)
+ final_query = params[:extras] ? (!extras.nil? ? UserInfo.where(user_id: extras) : nil) : nil
+
+ if !infos_query.empty?
+ query = !final_query.nil? ? final_query : nil
+
+ if infos_query["user_id"]
+ user_ids = []
+ UserInfo.all.each do |u|
+ user_ids << u.user_id if u.user_id.to_s =~ /^#{infos_query["user_id"]}.*$/
+ end
+ query = !query.nil? ? final_query.where(user_id: user_ids) : UserInfo.where(user_id: user_ids)
+ end
+
+ if infos_query["user_name"]
+ if !query.nil?
+ query = query.where("user_name LIKE ?", "%#{infos_query["user_name"]}%")
+ else
+ query = UserInfo.where("user_name LIKE ?", "%#{infos_query["user_name"]}%")
+ end
+ end
+
+ final_query = query
+ end
+
+ if !final_query.nil? && !user_query.empty?
+ final_query = final_query.where(user_id: User.where("email LIKE ?", "%#{user_query["email"]}%"))
+ elsif !user_query.empty?
+ final_query = UserInfo.where(user_id: User.where("email LIKE ?", "%#{user_query["email"]}%"))
+ end
+
+ if !final_query.nil? && !role_query.empty?
+ final_query = final_query.where(user_role_id: UserRole.where("name LIKE ?", "%#{role_query["role"]}%"))
+ elsif !role_query.empty?
+ final_query = UserInfo.where(user_role_id: UserRole.where("name LIKE ?", "%#{role_query["role"]}%"))
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page] && !final_query.instance_of?(Array)
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at, :user_id, :user_role_id, :googleid], [:user, :user_role])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # Returns a filtered query based on the parameters passed for teachers.
+ def teacher_filter
+ teacher_query = {}
+ params.each do |param|
+ next unless param[0] == "teacher_name" || param[0] == "subject_name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ teacher_query.merge!({ param[0] => param[1] })
+ end
+
+ teachers = UserInfo.where(user_role_id: UserRole.where(name: ["eduapp-teacher", "eduapp-admin-query", "eduapp-admin"]))
+ final_query = nil
+ filtered_users = nil
+ filtered_subjects = nil
+
+ if teacher_query["teacher_name"]
+ filtered_users = teachers.where("user_name LIKE ?", "%#{teacher_query["teacher_name"]}%")
+ end
+
+ if teacher_query["subject_name"]
+ filtered_subjects = Subject.where("name LIKE ?", "%#{teacher_query["subject_name"]}%")
+ end
+
+ if !filtered_users.nil? || !filtered_subjects.nil?
+ users = !filtered_users.nil? ? filtered_users : teachers
+ subjects = !filtered_subjects.nil? ? filtered_subjects : Subject.all
+
+ final_query = []
+ users.each do |u|
+ subjects.each do |s|
+ next if final_query.include?({ user: u, subject: s })
+ final_query << { user: u, subject: s } if u.teaching_list.include? s.id
+ end
+ end
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = array_paginate(final_query, params[:page])
+ final_query.each do |t|
+ t[:user] = UserInfo.find(t[:user][:id]).serializable_hash(except: [:created_at, :updated_at, :googleid, :calendar_event, :isLoggedWithGoogle, :profile_image, :user_role_id, :user_id], include: [:user])
+ t[:subject] = Subject.find(t[:subject][:id]).serializable_hash(except: [:created_at, :updated_at, :course_id, :color, :description], include: [:course])
+ end if !final_query.nil?
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /user_infos/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_users)
+ return
+ end
+ render json: @user_info
+ end
+
+ def system_user
+ render json: UserInfo.where(user_name: "eduapp_system", user_role_id: get_admin_role.id).first, status: :ok and return
+ end
+
+ # POST /user_infos
+ def create
+ if !check_perms_write!(get_user_roles.perms_users)
+ return
+ end
+ @user_info = UserInfo.new(user_info_params)
+ if @user_info.save
+ render json: @user_info, status: :created, location: @user_info
+ else
+ render json: @user_info.errors, status: :unprocessable_entity
+ end
+ end
+
+ # Adds a ```Subject``` ID to the ```UserInfo``` ```:teaching_list``` array.
+ def add_subject
+ if !check_perms_write!(get_user_roles.perms_users)
+ return
+ end
+ @user_info = UserInfo.where(user_id: params[:user_id]).first
+ if @user_info.teaching_list.include?(params[:subject_id])
+ render json: { message: "Subject already added" }, status: :unprocessable_entity and return
+ end
+ @user_info.teaching_list << Subject.find(params[:subject_id]).id
+ @user_info.save
+ render json: @user_info
+ end
+
+ # Adds a ```CalendarAnnotation``` ID to the ```UserInfo``` ```:calendar_event``` array.
+ def add_events
+ if !check_perms_write!(get_user_roles.perms_users)
+ return
+ end
+ @user_info = UserInfo.all
+ calendar_annotation = CalendarAnnotation.where(isPop: true)
+
+ @user_info.each do |user_info|
+ calendar_annotation.each do |annotation|
+ if !user_info.calendar_event.include?(annotation.id.to_s)
+ user_info.calendar_event << annotation.id
+ end
+ end
+ user_info.save
+ end
+
+ render json: @user_info
+ end
+
+ # Removes a ```CalendarAnnotation``` ID of the ```UserInfo``` ```:calendar_event``` array.
+ def remove_event
+ if !check_perms_write!(get_user_roles.perms_users)
+ return
+ end
+ @user_info = UserInfo.where(user_id: params[:user_id]).first
+ @user_info.calendar_event.delete(CalendarAnnotation.find(params[:calendar_event]).id)
+ @user_info.save
+ render json: @user_info
+ end
+
+ # Removes a ```Subject``` ID of the ```UserInfo``` ```:teaching_list``` array.
+ def remove_subject
+ if !check_perms_write!(get_user_roles.perms_users)
+ return
+ end
+ @user_info = UserInfo.where(user_id: params[:user_id]).first
+ @user_info.teaching_list.delete(Subject.find(params[:subject_id]).id)
+ @user_info.save
+ render json: @user_info
+ end
+
+ # PUT /user_infos/1
+ def update
+ if !can_update_self(@user_info.user_id)
+ if !check_perms_update!(get_user_roles.perms_users)
+ return
+ end
+ end
+
+ if @user_info.update(user_info_params)
+ @user_info.profile_image.recreate_versions!
+ render json: @user_info
+ else
+ render json: @user_info.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /user_infos/1
+ def destroy
+ if !check_perms_delete!(get_user_roles.perms_users, true, UserInfo.find(params[:id]).user_id)
+ return
+ end
+ @user_info.destroy
+ end
+
+ # Completely removes a ```User``` with it's respective
+ # ```Tuition```, ```JtiMatchList``` and ```UserInfo``` linked entries.
+ def destroyuser
+ if !check_perms_delete!(get_user_roles.perms_users, true, params[:id])
+ return
+ end
+ user = User.find(params[:id])
+ user_i = UserInfo.find_by(user_id: params[:id])
+
+ # Cannot delete a user if he's the last administrator.
+ if UserInfo.where(user_role_id: get_admin_role.id).count === 1 && user_i.user_role_id === get_admin_role.id
+ render json: { message: "Cannot delete the last admin." }, status: 403 and return
+ end
+
+ JtiMatchList.where(user_id: params[:id]).each do |jti|
+ jti.destroy
+ end
+
+ Tuition.where(user_id: params[:id]).each do |tuition|
+ tuition.destroy
+ end
+
+ if user_i.destroy
+ if user.destroy
+ render json: { message: "Deleted user successfully." }, status: :ok
+ else
+ render json: { message: "Couldn't delete user" }, status: 500
+ end
+ else
+ render json: { message: "Couldn't delete user info" }, status: 500
+ end
+ end
+
+ private
+
+ # Tests if the requester id and the current ```User``` IDs are the same.
+ def can_update_self(requester_id)
+ return true if requester_id === @current_user
+ return false
+ end
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_user_info
+ @user_info = UserInfo.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def user_info_params
+ params.permit(:extras, :user_name, :user_id, :user_role, :calendar_event, :profile_image, :teaching_list, :googleid, :isLoggedWithGoogle)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/user_roles_controller.rb b/backend/eduapp_db/app/controllers/user_roles_controller.rb
index 57465a56..25ffd02f 100644
--- a/backend/eduapp_db/app/controllers/user_roles_controller.rb
+++ b/backend/eduapp_db/app/controllers/user_roles_controller.rb
@@ -1,148 +1,153 @@
-class UserRolesController < ApplicationController
- before_action :set_user_role, only: [:show, :update, :destroy]
- before_action :authenticate_user!
- before_action :check_role!
-
- # GET /user_roles
- def index
- if params[:role_name]
- if !check_perms_query!(get_user_roles.perms_roles)
- return
- end
- @user_roles = UserRole.where(name: params[:role_name])
- elsif params[:user_id]
- if !check_perms_query_self!(get_user_roles.perms_roles, params[:user_id])
- return
- end
- @user_roles = UserRole.find(UserInfo.where(user_id: params[:user_id]).first.user_roles_id)
- else
- if !check_perms_all!(get_user_roles.perms_roles)
- return
- end
- @user_roles = UserRole.all
- end
-
- if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
- @user_roles = @user_roles.order(parse_filter_order(params[:order]))
- else
- @user_roles = @user_roles.order(name: :asc)
- end
-
- if params[:page]
- @user_roles = query_paginate(@user_roles, params[:page])
- end
-
- render json: @user_roles
- end
-
- # Returns a filtered query based on the parameters passed.
- def filter
- role_query = {}
- params.each do |param|
- next unless param[0] == "name"
- next unless param[1] != "null" && param[1].length > 0
-
- role_query.merge!({ param[0] => param[1] })
- end
-
- final_query = nil
-
- if role_query["name"]
- final_query = UserRole.where("name LIKE ?", "%#{role_query["name"]}%")
- end
-
- final_query = [] if final_query.nil?
-
- if params[:page]
- final_query = query_paginate(final_query, params[:page])
- final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at], [])
- end
-
- render json: { filtration: final_query }
- end
-
- # GET /user_roles/1
- def show
- return if !check_perms_query!(get_user_roles.perms_roles)
- render json: @user_role
- end
-
- # POST /user_roles
- def create
- return if !check_perms_write!(get_user_roles.perms_roles)
-
- @user_role = UserRole.new({
- name: params[:user_role][:name],
- description: params[:user_role][:description],
- perms_institution: params[:user_role][:perms_institution],
- perms_course: params[:user_role][:perms_course],
- perms_subjects: params[:user_role][:perms_subjects],
- perms_resources: params[:user_role][:perms_resources],
- perms_sessions: params[:user_role][:perms_sessions],
- perms_events: params[:user_role][:perms_events],
- perms_teachers: params[:user_role][:perms_teachers],
- perms_users: params[:user_role][:perms_users],
- perms_roles: params[:user_role][:perms_roles],
- perms_tuitions: params[:user_role][:perms_tuitions],
- perms_jti_matchlist: params[:user_role][:perms_jti_matchlist],
- perms_chat: params[:user_role][:perms_chat],
- perms_chat_participants: params[:user_role][:perms_chat_participants],
- perms_message: params[:user_role][:perms_message],
- perms_app_views: params[:user_role][:perms_app_views],
- })
-
- if @user_role.save
- render json: @user_role, status: :created, location: @user_role
- else
- render json: @user_role.errors, status: :unprocessable_entity
- end
- end
-
- # PUT /user_roles/1
- def update
- return if !check_perms_update!(get_user_roles.perms_roles, false, :null)
-
- if @user_role.update({
- name: params[:user_role][:name],
- description: params[:user_role][:description],
- perms_institution: params[:user_role][:perms_institution],
- perms_course: params[:user_role][:perms_course],
- perms_subjects: params[:user_role][:perms_subjects],
- perms_resources: params[:user_role][:perms_resources],
- perms_sessions: params[:user_role][:perms_sessions],
- perms_events: params[:user_role][:perms_events],
- perms_teachers: params[:user_role][:perms_teachers],
- perms_users: params[:user_role][:perms_users],
- perms_roles: params[:user_role][:perms_roles],
- perms_tuitions: params[:user_role][:perms_tuitions],
- perms_jti_matchlist: params[:user_role][:perms_jti_matchlist],
- perms_chat: params[:user_role][:perms_chat],
- perms_chat_participants: params[:user_role][:perms_chat_participants],
- perms_message: params[:user_role][:perms_message],
- perms_app_views: params[:user_role][:perms_app_views],
- })
- render json: @user_role
- else
- render json: @user_role.errors, status: :unprocessable_entity
- end
- end
-
- # DELETE /user_roles/1
- def destroy
- return if !check_perms_delete!(get_user_roles.perms_roles, false, :null)
-
- @user_role.destroy
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_user_role
- @user_role = UserRole.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def user_role_params
- params.require(:user_role).permit(:name, :description, :perms_institution, :perms_course, :perms_subjects, :perms_resources, :perms_sessions, :perms_events, :perms_teachers, :perms_users, :perms_roles, :perms_tuitions, :perms_jti_matchlist, :perms_chat, :perms_chat_participants, :perms_message, :perms_app_views)
- end
-end
+class UserRolesController < ApplicationController
+ before_action :set_user_role, only: [:show, :update, :destroy]
+ before_action :authenticate_user!
+ before_action :check_role!
+
+ # GET /user_roles
+ def index
+ if params[:role_name]
+ if !check_perms_query!(get_user_roles.perms_roles)
+ return
+ end
+ @user_roles = UserRole.where(name: params[:role_name])
+ elsif params[:user_id]
+ if !check_perms_query_self!(get_user_roles.perms_roles, params[:user_id])
+ return
+ end
+ @user_roles = UserRole.find(UserInfo.where(user_id: params[:user_id]).first.user_roles_id)
+ else
+ if !check_perms_all!(get_user_roles.perms_roles)
+ return
+ end
+ @user_roles = UserRole.all
+ end
+
+ if !params[:order].nil? && Base64.decode64(params[:order]) != "null"
+ @user_roles = @user_roles.order(parse_filter_order(params[:order]))
+ else
+ @user_roles = @user_roles.order(name: :asc)
+ end
+
+ if params[:page]
+ @user_roles = query_paginate(@user_roles, params[:page])
+ end
+
+ render json: @user_roles
+ end
+
+ # Returns a filtered query based on the parameters passed.
+ def filter
+ role_query = {}
+ params.each do |param|
+ next unless param[0] == "name"
+ next unless param[1] != "null" && param[1].length > 0
+
+ role_query.merge!({ param[0] => param[1] })
+ end
+
+ final_query = nil
+
+ if role_query["name"]
+ final_query = UserRole.where("name LIKE ?", "%#{role_query["name"]}%")
+ end
+
+ final_query = [] if final_query.nil?
+
+ if params[:page]
+ final_query = query_paginate(final_query, params[:page])
+ final_query = serialize_each(final_query[:current_page], [:created_at, :updated_at], [])
+ end
+
+ render json: { filtration: final_query }
+ end
+
+ # GET /user_roles/1
+ def show
+ if !check_perms_query!(get_user_roles.perms_roles,false) && !check_perms_query_self!(get_user_roles.perms_roles, current_user)
+ deny_perms_access!
+ return
+ end
+ render json: @user_role
+ end
+
+ # POST /user_roles
+ def create
+ return if !check_perms_write!(get_user_roles.perms_roles)
+
+ @user_role = UserRole.new({
+ name: params[:user_role][:name],
+ description: params[:user_role][:description],
+ perms_institution: params[:user_role][:perms_institution],
+ perms_course: params[:user_role][:perms_course],
+ perms_subjects: params[:user_role][:perms_subjects],
+ perms_resources: params[:user_role][:perms_resources],
+ perms_sessions: params[:user_role][:perms_sessions],
+ perms_session_chats: params[:user_role][:perms_session_chats],
+ perms_events: params[:user_role][:perms_events],
+ perms_teachers: params[:user_role][:perms_teachers],
+ perms_users: params[:user_role][:perms_users],
+ perms_roles: params[:user_role][:perms_roles],
+ perms_tuitions: params[:user_role][:perms_tuitions],
+ perms_jti_matchlist: params[:user_role][:perms_jti_matchlist],
+ perms_chat: params[:user_role][:perms_chat],
+ perms_chat_participants: params[:user_role][:perms_chat_participants],
+ perms_message: params[:user_role][:perms_message],
+ perms_app_views: params[:user_role][:perms_app_views],
+ })
+
+ if @user_role.save
+ render json: @user_role, status: :created, location: @user_role
+ else
+ render json: @user_role.errors, status: :unprocessable_entity
+ end
+ end
+
+ # PUT /user_roles/1
+ def update
+ return if !check_perms_update!(get_user_roles.perms_roles, false, :null)
+
+ if @user_role.update({
+ name: params[:user_role][:name],
+ description: params[:user_role][:description],
+ perms_institution: params[:user_role][:perms_institution],
+ perms_course: params[:user_role][:perms_course],
+ perms_subjects: params[:user_role][:perms_subjects],
+ perms_resources: params[:user_role][:perms_resources],
+ perms_sessions: params[:user_role][:perms_sessions],
+ perms_session_chats: params[:user_role][:perms_session_chats],
+ perms_events: params[:user_role][:perms_events],
+ perms_teachers: params[:user_role][:perms_teachers],
+ perms_users: params[:user_role][:perms_users],
+ perms_roles: params[:user_role][:perms_roles],
+ perms_tuitions: params[:user_role][:perms_tuitions],
+ perms_jti_matchlist: params[:user_role][:perms_jti_matchlist],
+ perms_chat: params[:user_role][:perms_chat],
+ perms_chat_participants: params[:user_role][:perms_chat_participants],
+ perms_message: params[:user_role][:perms_message],
+ perms_app_views: params[:user_role][:perms_app_views],
+ })
+ render json: @user_role
+ else
+ render json: @user_role.errors, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE /user_roles/1
+ def destroy
+ return if !check_perms_delete!(get_user_roles.perms_roles, false, :null)
+
+ @user_role.destroy
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_user_role
+ @user_role = UserRole.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def user_role_params
+ params.require(:user_role).permit(:name, :description, :perms_institution, :perms_course, :perms_subjects, :perms_resources, :perms_sessions, :perms_session_chats, :perms_events, :perms_teachers, :perms_users, :perms_roles, :perms_tuitions, :perms_jti_matchlist, :perms_chat, :perms_chat_participants, :perms_message, :perms_app_views)
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/users/confirmations_controller.rb b/backend/eduapp_db/app/controllers/users/confirmations_controller.rb
index fa535c0a..d08be131 100644
--- a/backend/eduapp_db/app/controllers/users/confirmations_controller.rb
+++ b/backend/eduapp_db/app/controllers/users/confirmations_controller.rb
@@ -1,30 +1,30 @@
-# frozen_string_literal: true
-
-class Users::ConfirmationsController < Devise::ConfirmationsController
- # GET /resource/confirmation/new
- # def new
- # super
- # end
-
- # POST /resource/confirmation
- # def create
- # super
- # end
-
- # GET /resource/confirmation?confirmation_token=abcdef
- # def show
- # super
- # end
-
- # protected
-
- # The path used after resending confirmation instructions.
- # def after_resending_confirmation_instructions_path_for(resource_name)
- # super(resource_name)
- # end
-
- # The path used after confirmation.
- # def after_confirmation_path_for(resource_name, resource)
- # super(resource_name, resource)
- # end
-end
+# frozen_string_literal: true
+
+class Users::ConfirmationsController < Devise::ConfirmationsController
+ # GET /resource/confirmation/new
+ # def new
+ # super
+ # end
+
+ # POST /resource/confirmation
+ # def create
+ # super
+ # end
+
+ # GET /resource/confirmation?confirmation_token=abcdef
+ # def show
+ # super
+ # end
+
+ # protected
+
+ # The path used after resending confirmation instructions.
+ # def after_resending_confirmation_instructions_path_for(resource_name)
+ # super(resource_name)
+ # end
+
+ # The path used after confirmation.
+ # def after_confirmation_path_for(resource_name, resource)
+ # super(resource_name, resource)
+ # end
+end
diff --git a/backend/eduapp_db/app/controllers/users/passwords_controller.rb b/backend/eduapp_db/app/controllers/users/passwords_controller.rb
index 2f0650c8..622d8b46 100644
--- a/backend/eduapp_db/app/controllers/users/passwords_controller.rb
+++ b/backend/eduapp_db/app/controllers/users/passwords_controller.rb
@@ -1,77 +1,77 @@
-class Users::PasswordsController < Devise::PasswordsController
- # When the auth is implemented use this
- # before_action :authenticate_user! , only: [:get_reset_password_token,:do_reset_password]
-
- # Sends a confirmation code via email to the user.
- def send_change_password_instructions
- old_password = params[:old_password]
- @user = User.find_by(email: params[:email])
- # When the auth is implemented use this
- # @user = current_user
- if @user.present?
- if @user.valid_password?(old_password)
- PasswordMailer.with(user: @user).send_confirmation_email.deliver_now
- render json: { status: "success", message: "email sent to " + @user.email }
- else
- render json: { status: "failure", message: "Invalid old password" }
- end
- else
- render json: { status: "failure", message: "User not found" }
- end
- end
-
- # Changes the user's password via a confirmation code method.
- def change_password
- # Use below when the auth is implemented
- # user = current_user
- # Instead use this, but you should pass the user email in the params
- user = User.find_by(email: params[:email])
- new_password = Base64.decode64(params[:new_password])
- confirm_password = Base64.decode64(params[:confirm_password])
- confirmation_code = params[:confirmation_code]
- if user.present?
- if new_password == confirm_password && user.confirmation_code == confirmation_code
- if user.confirmation_code_exp_time > DateTime.now
- user.password = new_password
- user.save
- render json: { status: "success", message: "Password changed successfully." }
- else
- render json: { status: "failure", message: "Expired code" }
- end
- else
- render json: { message: "Password change failed." }, status: :unprocessable_entity
- end
- else
- render json: { message: "User not found." }, status: :unprocessable_entity
- end
- end
-
- # Resets a user's password.
- def do_reset_password
- user = User.find_by(email: params[:email])
- if user.reset_password_token == params[:token]
- user.reset_password(params[:password], params[:password_confirmation])
- render json: { status: "success", message: "Password changed successfully." }
- else
- render json: { status: "failure", message: "Invalid token" }
- end
- end
-
- # Sends a password reset link to the user's email.
- def send_reset_password_link
- user = User.find_by(email: params[:email])
- if user.present?
- user.send(:set_reset_password_token)
- user.save
- @token = user.reset_password_token
- if @token.present?
- PasswordMailer.with(user: user).send_reset_email.deliver_now
- render json: { message: "email sent to " + user.email, status: "success", expires_in: 15.minutes.from_now } and return
- else
- render json: { message: "email not sent", status: "failure, no token" } and return
- end
- else
- render json: { status: "failure", message: "User not found" } and return
- end
- end
-end
+class Users::PasswordsController < Devise::PasswordsController
+ # When the auth is implemented use this
+ # before_action :authenticate_user! , only: [:get_reset_password_token,:do_reset_password]
+
+ # Sends a confirmation code via email to the user.
+ def send_change_password_instructions
+ old_password = params[:old_password]
+ @user = User.find_by(email: params[:email])
+ # When the auth is implemented use this
+ # @user = current_user
+ if @user.present?
+ if @user.valid_password?(old_password)
+ PasswordMailer.with(user: @user).send_confirmation_email.deliver_now
+ render json: { status: "success", message: "email sent to " + @user.email }
+ else
+ render json: { status: "failure", message: "Invalid old password" }
+ end
+ else
+ render json: { status: "failure", message: "User not found" }
+ end
+ end
+
+ # Changes the user's password via a confirmation code method.
+ def change_password
+ # Use below when the auth is implemented
+ # user = current_user
+ # Instead use this, but you should pass the user email in the params
+ user = User.find_by(email: params[:email])
+ new_password = Base64.decode64(params[:new_password])
+ confirm_password = Base64.decode64(params[:confirm_password])
+ confirmation_code = params[:confirmation_code]
+ if user.present?
+ if new_password == confirm_password && user.confirmation_code == confirmation_code
+ if user.confirmation_code_exp_time > DateTime.now
+ user.password = new_password
+ user.save
+ render json: { status: "success", message: "Password changed successfully." }
+ else
+ render json: { status: "failure", message: "Expired code" }
+ end
+ else
+ render json: { message: "Password change failed." }, status: :unprocessable_entity
+ end
+ else
+ render json: { message: "User not found." }, status: :unprocessable_entity
+ end
+ end
+
+ # Resets a user's password.
+ def do_reset_password
+ user = User.find_by(email: params[:email])
+ if user.reset_password_token == params[:token]
+ user.reset_password(params[:password], params[:password_confirmation])
+ render json: { status: "success", message: "Password changed successfully." }
+ else
+ render json: { status: "failure", message: "Invalid token" }
+ end
+ end
+
+ # Sends a password reset link to the user's email.
+ def send_reset_password_link
+ user = User.find_by(email: params[:email])
+ if user.present?
+ user.send(:set_reset_password_token)
+ user.save
+ @token = user.reset_password_token
+ if @token.present?
+ PasswordMailer.with(user: user).send_reset_email.deliver_now
+ render json: { message: "email sent to " + user.email, status: "success", expires_in: 15.minutes.from_now } and return
+ else
+ render json: { message: "email not sent", status: "failure, no token" } and return
+ end
+ else
+ render json: { status: "failure", message: "User not found" } and return
+ end
+ end
+end
diff --git a/backend/eduapp_db/app/controllers/users/registrations_controller.rb b/backend/eduapp_db/app/controllers/users/registrations_controller.rb
index 16c4c51a..c6d27237 100644
--- a/backend/eduapp_db/app/controllers/users/registrations_controller.rb
+++ b/backend/eduapp_db/app/controllers/users/registrations_controller.rb
@@ -56,6 +56,9 @@ def edit_user
payload.each do |p|
user.update_attribute(p[0],p[1])
end
+ user.user_info.update_attribute(:user_name, user.username);
+ user.user_info.update_attribute(:profile_image, user.profile_image);
+
rescue => error
render json: { errors: error}, status: :unprocessable_entity
return
diff --git a/backend/eduapp_db/app/controllers/users/sessions_controller.rb b/backend/eduapp_db/app/controllers/users/sessions_controller.rb
index 76943fa1..ba9e8eef 100644
--- a/backend/eduapp_db/app/controllers/users/sessions_controller.rb
+++ b/backend/eduapp_db/app/controllers/users/sessions_controller.rb
@@ -13,7 +13,7 @@ def create
sign_in(resource_name, resource)
yield resource if block_given?
- @user_info = UserInfo.where(user_id: resource.id).first.serializable_hash(:include => [:user, :user_role], :except => [:user_role_id, :googleid, :created_at, :updated_at])
+ @user_info = UserInfo.where(user_id: resource.id).first.serializable_hash(:include => [:user, :user_role, :profile_image], :except => [:user_role_id, :googleid, :created_at, :updated_at])
respond_with @user_info
end
@@ -63,7 +63,7 @@ def glogin_unlink
user.save
render json: {status: 200, message: "Successfully unlinked"}
return
-
+
end
def glogin_login
@@ -75,14 +75,13 @@ def glogin_login
@user_info = UserInfo.where(user_id: user.id).first.serializable_hash(:include => [:user, :user_role], :except => [:user_role_id, :googleid, :created_at, :updated_at])
respond_with @user_info
-
+
end
private
def respond_with(resource, _opts = {})
token = User.generate_token(resource, request.remote_ip)
-
headers["EduAuth"] = "Bearer #{token}"
headers["Access-Control-Allow-Origin"] = "*"
headers["Access-Control-Allow-Methods"] = "POST, PUT, DELETE, GET, OPTIONS"
diff --git a/backend/eduapp_db/app/jobs/application_job.rb b/backend/eduapp_db/app/jobs/application_job.rb
index d394c3d1..8eb2b33e 100644
--- a/backend/eduapp_db/app/jobs/application_job.rb
+++ b/backend/eduapp_db/app/jobs/application_job.rb
@@ -1,7 +1,7 @@
-class ApplicationJob < ActiveJob::Base
- # Automatically retry jobs that encountered a deadlock
- # retry_on ActiveRecord::Deadlocked
-
- # Most jobs are safe to ignore if the underlying records are no longer available
- # discard_on ActiveJob::DeserializationError
-end
+class ApplicationJob < ActiveJob::Base
+ # Automatically retry jobs that encountered a deadlock
+ # retry_on ActiveRecord::Deadlocked
+
+ # Most jobs are safe to ignore if the underlying records are no longer available
+ # discard_on ActiveJob::DeserializationError
+end
diff --git a/backend/eduapp_db/app/mailers/application_mailer.rb b/backend/eduapp_db/app/mailers/application_mailer.rb
index e511d10a..19a6137d 100644
--- a/backend/eduapp_db/app/mailers/application_mailer.rb
+++ b/backend/eduapp_db/app/mailers/application_mailer.rb
@@ -1,9 +1,9 @@
-class ApplicationMailer < ActionMailer::Base
- default from: 'eduappdevelopment@gmail.com'
- layout 'mailer'
-
- def configure_permitted_parameters
- devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation) }
- devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password)}
- end
-end
+class ApplicationMailer < ActionMailer::Base
+ default from: 'eduappdevelopment@gmail.com'
+ layout 'mailer'
+
+ def configure_permitted_parameters
+ devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation) }
+ devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password)}
+ end
+end
diff --git a/backend/eduapp_db/app/mailers/password_mailer.rb b/backend/eduapp_db/app/mailers/password_mailer.rb
index 9eaeb3a6..c4b70253 100644
--- a/backend/eduapp_db/app/mailers/password_mailer.rb
+++ b/backend/eduapp_db/app/mailers/password_mailer.rb
@@ -1,29 +1,29 @@
-class PasswordMailer < ApplicationMailer
- layout "mailer"
-
- def send_reset_email
- @user = params[:user]
- if @user.present?
- token = @user.reset_password_token
- @url = ENV.fetch("REACT_APP_FRONTEND_ENDPOINT") + "/password/reset?email=" + @user.email + "&token=" + token
- mail(to: @user.email, subject: "EduApp Password Reset", url: @url)
- else
- render json: { status: "failure" }
- end
- end
-
- def send_confirmation_email
- @user = params[:user]
- @confirmation_code = SecureRandom.hex
- @expireCodeDate = DateTime.now + 20.minutes
- if @user.present?
- @user.confirmation_code = @confirmation_code
- @user.confirmation_code_exp_time = @expireCodeDate
- @user.save
- mail(to: @user.email, subject: "EduApp Confirmation", confirmation_code: @confirmation_code)
- render json: { status: "success", expires_in: @expireCodeDate, message: "code sent to " + @user.email }
- else
- render json: { status: "failure", message: "User not found in send_confirmation_email" }
- end
- end
+class PasswordMailer < ApplicationMailer
+ layout "mailer"
+
+ def send_reset_email
+ @user = params[:user]
+ if @user.present?
+ token = @user.reset_password_token
+ @url = ENV.fetch("REACT_APP_FRONTEND_ENDPOINT") + "/password/reset?email=" + @user.email + "&token=" + token
+ mail(to: @user.email, subject: "EduApp Password Reset", url: @url)
+ else
+ render json: { status: "failure" }
+ end
+ end
+
+ def send_confirmation_email
+ @user = params[:user]
+ @confirmation_code = SecureRandom.hex
+ @expireCodeDate = DateTime.now + 20.minutes
+ if @user.present?
+ @user.confirmation_code = @confirmation_code
+ @user.confirmation_code_exp_time = @expireCodeDate
+ @user.save
+ mail(to: @user.email, subject: "EduApp Confirmation", confirmation_code: @confirmation_code)
+ render json: { status: "success", expires_in: @expireCodeDate, message: "code sent to " + @user.email }
+ else
+ render json: { status: "failure", message: "User not found in send_confirmation_email" }
+ end
+ end
end
\ No newline at end of file
diff --git a/backend/eduapp_db/app/models/application_record.rb b/backend/eduapp_db/app/models/application_record.rb
index 10a4cba8..7f64061b 100644
--- a/backend/eduapp_db/app/models/application_record.rb
+++ b/backend/eduapp_db/app/models/application_record.rb
@@ -1,3 +1,3 @@
-class ApplicationRecord < ActiveRecord::Base
- self.abstract_class = true
-end
+class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+end
diff --git a/backend/eduapp_db/app/models/calendar_annotation.rb b/backend/eduapp_db/app/models/calendar_annotation.rb
index 90d0701b..b31bd64f 100644
--- a/backend/eduapp_db/app/models/calendar_annotation.rb
+++ b/backend/eduapp_db/app/models/calendar_annotation.rb
@@ -1,5 +1,5 @@
-class CalendarAnnotation < ApplicationRecord
- # belongs_to :course
- belongs_to :user
- belongs_to :subject
-end
+class CalendarAnnotation < ApplicationRecord
+ # belongs_to :course
+ belongs_to :user
+ belongs_to :subject
+end
diff --git a/backend/eduapp_db/app/models/chat_base.rb b/backend/eduapp_db/app/models/chat_base.rb
index 06b0c9e0..779fc990 100644
--- a/backend/eduapp_db/app/models/chat_base.rb
+++ b/backend/eduapp_db/app/models/chat_base.rb
@@ -1,3 +1,5 @@
-class ChatBase < ApplicationRecord
- has_one_attached :chat_image
-end
+class ChatBase < ApplicationRecord
+ has_one_attached :chat_image
+ has_many :chat_participants, dependent: :destroy
+ has_many :chat_messages, dependent: :destroy
+end
diff --git a/backend/eduapp_db/app/models/chat_base_info.rb b/backend/eduapp_db/app/models/chat_base_info.rb
index df083d85..cc68eae9 100644
--- a/backend/eduapp_db/app/models/chat_base_info.rb
+++ b/backend/eduapp_db/app/models/chat_base_info.rb
@@ -1,3 +1,3 @@
-class ChatBaseInfo < ApplicationRecord
- belongs_to :chat_base
-end
+class ChatBaseInfo < ApplicationRecord
+ belongs_to :chat_base
+end
diff --git a/backend/eduapp_db/app/models/chat_message.rb b/backend/eduapp_db/app/models/chat_message.rb
index 1ea2b5f0..50b40684 100644
--- a/backend/eduapp_db/app/models/chat_message.rb
+++ b/backend/eduapp_db/app/models/chat_message.rb
@@ -1,4 +1,4 @@
-class ChatMessage < ApplicationRecord
- belongs_to :chat_base
- belongs_to :user
-end
+class ChatMessage < ApplicationRecord
+ belongs_to :chat_base
+ belongs_to :user
+end
diff --git a/backend/eduapp_db/app/models/chat_participant.rb b/backend/eduapp_db/app/models/chat_participant.rb
index c7d965cc..dcc48ca6 100644
--- a/backend/eduapp_db/app/models/chat_participant.rb
+++ b/backend/eduapp_db/app/models/chat_participant.rb
@@ -1,9 +1,9 @@
-class ChatParticipant < ApplicationRecord
- belongs_to :chat_base
- belongs_to :user
-
- enum status: {
- "Offline" => 0,
- "Online" => 1,
- }
-end
+class ChatParticipant < ApplicationRecord
+ belongs_to :chat_base
+ belongs_to :user
+
+ enum status: {
+ "Offline" => 0,
+ "Online" => 1,
+ }
+end
diff --git a/backend/eduapp_db/app/models/course.rb b/backend/eduapp_db/app/models/course.rb
index dedc0c26..ae1481a7 100644
--- a/backend/eduapp_db/app/models/course.rb
+++ b/backend/eduapp_db/app/models/course.rb
@@ -1,6 +1,6 @@
-class Course < ApplicationRecord
- belongs_to :institution
- has_many :eduapp_user_session
- has_many :resource
- has_one :calendar_annotation
-end
+class Course < ApplicationRecord
+ belongs_to :institution
+ has_many :eduapp_user_session
+ has_many :resource
+ has_one :calendar_annotation
+end
diff --git a/backend/eduapp_db/app/models/eduapp_user_session.rb b/backend/eduapp_db/app/models/eduapp_user_session.rb
index fe978cb9..81212e76 100644
--- a/backend/eduapp_db/app/models/eduapp_user_session.rb
+++ b/backend/eduapp_db/app/models/eduapp_user_session.rb
@@ -1,3 +1,3 @@
-class EduappUserSession < ApplicationRecord
- belongs_to :subject
-end
+class EduappUserSession < ApplicationRecord
+ belongs_to :subject
+end
diff --git a/backend/eduapp_db/app/models/institution.rb b/backend/eduapp_db/app/models/institution.rb
index df72d5a0..9973b578 100644
--- a/backend/eduapp_db/app/models/institution.rb
+++ b/backend/eduapp_db/app/models/institution.rb
@@ -1,3 +1,3 @@
-class Institution < ApplicationRecord
- has_many :course
-end
+class Institution < ApplicationRecord
+ has_many :course
+end
diff --git a/backend/eduapp_db/app/models/jti_match_list.rb b/backend/eduapp_db/app/models/jti_match_list.rb
index 066a3de9..ecebb7e7 100644
--- a/backend/eduapp_db/app/models/jti_match_list.rb
+++ b/backend/eduapp_db/app/models/jti_match_list.rb
@@ -1,3 +1,3 @@
-class JtiMatchList < ApplicationRecord
- belongs_to :user
-end
+class JtiMatchList < ApplicationRecord
+ belongs_to :user
+end
diff --git a/backend/eduapp_db/app/models/push_notification.rb b/backend/eduapp_db/app/models/push_notification.rb
new file mode 100644
index 00000000..9f7b9eda
--- /dev/null
+++ b/backend/eduapp_db/app/models/push_notification.rb
@@ -0,0 +1,4 @@
+class PushNotification < ApplicationRecord
+ belongs_to :user
+
+end
diff --git a/backend/eduapp_db/app/models/resource.rb b/backend/eduapp_db/app/models/resource.rb
index c732b42a..37bafd1a 100644
--- a/backend/eduapp_db/app/models/resource.rb
+++ b/backend/eduapp_db/app/models/resource.rb
@@ -1,6 +1,6 @@
-class Resource < ApplicationRecord
- belongs_to :subject
- belongs_to :user
-
- has_many_attached :files
-end
+class Resource < ApplicationRecord
+ belongs_to :subject
+ belongs_to :user
+
+ has_many_attached :files
+end
diff --git a/backend/eduapp_db/app/models/subject.rb b/backend/eduapp_db/app/models/subject.rb
index 065b1dd4..9f965d15 100644
--- a/backend/eduapp_db/app/models/subject.rb
+++ b/backend/eduapp_db/app/models/subject.rb
@@ -1,3 +1,5 @@
-class Subject < ApplicationRecord
- belongs_to :course
-end
+class Subject < ApplicationRecord
+ belongs_to :course
+ has_many :subjects_user
+ has_many :users, through: :subjects_user
+end
diff --git a/backend/eduapp_db/app/models/subjects_user.rb b/backend/eduapp_db/app/models/subjects_user.rb
new file mode 100644
index 00000000..d12136f6
--- /dev/null
+++ b/backend/eduapp_db/app/models/subjects_user.rb
@@ -0,0 +1,4 @@
+class SubjectsUser < ApplicationRecord
+ belongs_to :subject
+ belongs_to :user
+end
diff --git a/backend/eduapp_db/app/models/tuition.rb b/backend/eduapp_db/app/models/tuition.rb
index 6529ecba..f5b5cd72 100644
--- a/backend/eduapp_db/app/models/tuition.rb
+++ b/backend/eduapp_db/app/models/tuition.rb
@@ -1,4 +1,4 @@
-class Tuition < ApplicationRecord
- belongs_to :course
- belongs_to :user
-end
+class Tuition < ApplicationRecord
+ belongs_to :course
+ belongs_to :user
+end
diff --git a/backend/eduapp_db/app/models/user.rb b/backend/eduapp_db/app/models/user.rb
index fe4fe24d..e86d736d 100644
--- a/backend/eduapp_db/app/models/user.rb
+++ b/backend/eduapp_db/app/models/user.rb
@@ -1,119 +1,123 @@
-class User < ApplicationRecord
- require "jwt"
-
- devise :database_authenticatable,
- :jwt_authenticatable,
- :registerable,
- :trackable,
- :recoverable,
- jwt_revocation_strategy: self
-
- has_one :user_info
-
- # Allow user to login either with username and email
-
- attr_writer :login
-
- def login
- @login || self.username || self.email
- end
-
- def self.find_for_database_authentication(warden_conditions)
- conditions = warden_conditions.dup
- login = conditions.delete(:login)
- where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.strip.downcase }]).first
- end
-
- # JWT Management
-
- @secret = ENV.fetch("RAILS_SECRET_KEY")
-
- # Generates a new ```JtiMatchList``` entry for the user.
- def self.generate_jti(user, user_ip)
- iat, exp = self.gen_exp
- jti = self.gen_jti iat
-
- jwtEntry = JtiMatchList.new(
- user_id: user["user_id"],
- jti: jti,
- exp: exp,
- access_ip: user_ip,
- )
- if jwtEntry.save
- return true
- else
- return { error: jwtEntry.errors.messages }
- end
- end
-
- # Generates a JWT Token for a user.
- def self.generate_token(user, user_ip)
- iat, exp = self.gen_exp
-
- userTotalJti = JtiMatchList.where(user_id: user["user_id"]).order(created_at: :desc)
- userTotalJti.last.destroy if userTotalJti.count === 4 # Logs out the last connection's IP for a new connection.
-
- existingUserJti = JtiMatchList.where(user_id: user["user_id"], access_ip: user_ip)
- if existingUserJti.count > 0
- jti = existingUserJti.first.jti
- else
- if self.generate_jti(user, user_ip) === true
- existingUserJti = JtiMatchList.where(user_id: user["user_id"], access_ip: user_ip)
- else
- return { error: "Failed to generate token." }
- end
- end
-
- user_role = UserRole.find(UserInfo.where(user_id: existingUserJti[0].user_id).first.user_role_id)
- return { error: "Failed to find user role." } if !user_role
-
- payload = {
- iat: iat,
- exp: exp,
- aud: user_role.name,
- jti: jti.nil? ? existingUserJti[0].jti : jti,
- sub: existingUserJti[0].user_id,
- }
-
- if existingUserJti.update(exp: exp)
- return JWT.encode payload, @secret, "HS256"
- else
- return { error: jwtEntry.errors.messages }
- end
- end
-
- # Decodes a JWT Token.
- def self.unlock_token(token)
- begin
- return JWT.decode token, @secret, true, { verify_jti: true, aud: "user", algorithm: "HS256" }
- rescue JWT::ExpiredSignature => expired
- return { error: "Token has expired: #{expired}" }
- rescue JWT::VerificationError, JWT::DecodeError, JWT::ImmatureSignature => err
- return { error: "Verify Token is invalid: #{err}" }
- end
- end
-
- # Revokes a JWT Token from a user.
- def self.revoke_token(user, user_ip)
- revokedUserJti = JtiMatchList.where(user_id: user, access_ip: user_ip)
-
- iat, exp = self.gen_exp
- if revokedUserJti.update(exp: exp, jti: self.gen_jti(iat))
- return true
- else
- return { error: revokedUserJti.errors.messages }
- end
- end
-
- private
-
- # Generates an expiration for an hour in time.
- def self.gen_exp
- return Time.now.to_i, 1.hour.from_now.to_i # [iat, exp]
- end
-
- # Returnes a newly signed JTI.
- def self.gen_jti(issued_at)
- return Digest::SHA256.hexdigest([@secret, issued_at].join(":").to_s)
- end
-end
+class User < ApplicationRecord
+ require "jwt"
+
+ devise :database_authenticatable,
+ :jwt_authenticatable,
+ :registerable,
+ :trackable,
+ :recoverable,
+ jwt_revocation_strategy: self
+
+ has_one :user_info
+ has_many :tuitions
+ has_many :subjects_user
+ has_many :subjects, through: :subjects_user
+ has_many :push_notifications
+
+ # Allow user to login either with username and email
+
+ attr_writer :login
+
+ def login
+ @login || self.username || self.email
+ end
+
+ def self.find_for_database_authentication(warden_conditions)
+ conditions = warden_conditions.dup
+ login = conditions.delete(:login)
+ where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.strip.downcase }]).first
+ end
+
+ # JWT Management
+
+ @secret = ENV.fetch("RAILS_SECRET_KEY")
+
+ # Generates a new ```JtiMatchList``` entry for the user.
+ def self.generate_jti(user, user_ip)
+ iat, exp = self.gen_exp
+ jti = self.gen_jti iat
+
+ jwtEntry = JtiMatchList.new(
+ user_id: user["user_id"],
+ jti: jti,
+ exp: exp,
+ access_ip: user_ip,
+ )
+ if jwtEntry.save
+ return true
+ else
+ return { error: jwtEntry.errors.messages }
+ end
+ end
+
+ # Generates a JWT Token for a user.
+ def self.generate_token(user, user_ip)
+ iat, exp = self.gen_exp
+
+ userTotalJti = JtiMatchList.where(user_id: user["user_id"]).order(created_at: :desc)
+ userTotalJti.last.destroy if userTotalJti.count === 4 # Logs out the last connection's IP for a new connection.
+
+ existingUserJti = JtiMatchList.where(user_id: user["user_id"], access_ip: user_ip)
+ if existingUserJti.count > 0
+ jti = existingUserJti.first.jti
+ else
+ if self.generate_jti(user, user_ip) === true
+ existingUserJti = JtiMatchList.where(user_id: user["user_id"], access_ip: user_ip)
+ else
+ return { error: "Failed to generate token." }
+ end
+ end
+
+ user_role = UserRole.find(UserInfo.where(user_id: existingUserJti[0].user_id).first.user_role_id)
+ return { error: "Failed to find user role." } if !user_role
+
+ payload = {
+ iat: iat,
+ exp: exp,
+ aud: user_role.name,
+ jti: jti.nil? ? existingUserJti[0].jti : jti,
+ sub: existingUserJti[0].user_id,
+ }
+
+ if existingUserJti.update(exp: exp)
+ return JWT.encode payload, @secret, "HS256"
+ else
+ return { error: jwtEntry.errors.messages }
+ end
+ end
+
+ # Decodes a JWT Token.
+ def self.unlock_token(token)
+ begin
+ return JWT.decode token, @secret, true, { verify_jti: true, aud: "user", algorithm: "HS256" }
+ rescue JWT::ExpiredSignature => expired
+ return { error: "Token has expired: #{expired}" }
+ rescue JWT::VerificationError, JWT::DecodeError, JWT::ImmatureSignature => err
+ return { error: "Verify Token is invalid: #{err}" }
+ end
+ end
+
+ # Revokes a JWT Token from a user.
+ def self.revoke_token(user, user_ip)
+ revokedUserJti = JtiMatchList.where(user_id: user, access_ip: user_ip)
+
+ iat, exp = self.gen_exp
+ if revokedUserJti.update(exp: exp, jti: self.gen_jti(iat))
+ return true
+ else
+ return { error: revokedUserJti.errors.messages }
+ end
+ end
+
+ private
+
+ # Generates an expiration for an hour in time.
+ def self.gen_exp
+ return Time.now.to_i, 1.hour.from_now.to_i # [iat, exp]
+ end
+
+ # Returnes a newly signed JTI.
+ def self.gen_jti(issued_at)
+ return Digest::SHA256.hexdigest([@secret, issued_at].join(":").to_s)
+ end
+end
diff --git a/backend/eduapp_db/app/models/user_info.rb b/backend/eduapp_db/app/models/user_info.rb
index b9716b1d..1b603478 100644
--- a/backend/eduapp_db/app/models/user_info.rb
+++ b/backend/eduapp_db/app/models/user_info.rb
@@ -1,13 +1,21 @@
-class UserInfo < ApplicationRecord
- belongs_to :user
- belongs_to :user_role
-
- # Mainly used for the name searcher when creating a chat in the App.
- def self.search_name(pattern)
- if pattern.blank?
- all
- else
- order(user_name: :asc).where("user_name LIKE ?", "%#{pattern}%")
- end
- end
-end
+class UserInfo < ApplicationRecord
+ belongs_to :user
+ belongs_to :user_role
+
+ mount_uploader :profile_image, ProfileImageUploader
+ # Mainly used for the name searcher when creating a chat in the App.
+ def self.search_name(pattern)
+ if pattern.blank?
+ self
+ else
+ order(user_name: :asc).where("user_name ILIKE :q", q: "%#{pattern}%")
+ end
+ end
+ def self.search_email(pattern)
+ if pattern.blank?
+ self
+ else
+ order("users.email" => :asc).joins(:user).where("users.email LIKE ?", "%#{pattern}%")
+ end
+ end
+end
diff --git a/backend/eduapp_db/app/models/user_role.rb b/backend/eduapp_db/app/models/user_role.rb
index e1897f56..ffeadb6a 100644
--- a/backend/eduapp_db/app/models/user_role.rb
+++ b/backend/eduapp_db/app/models/user_role.rb
@@ -1,3 +1,3 @@
-class UserRole < ApplicationRecord
- has_one :user_info
-end
+class UserRole < ApplicationRecord
+ has_one :user_info
+end
diff --git a/backend/eduapp_db/app/serializers/calendar_annotation_serializer.rb b/backend/eduapp_db/app/serializers/calendar_annotation_serializer.rb
index bbdef0fa..9d5d7cef 100644
--- a/backend/eduapp_db/app/serializers/calendar_annotation_serializer.rb
+++ b/backend/eduapp_db/app/serializers/calendar_annotation_serializer.rb
@@ -1,5 +1,5 @@
-class CalendarAnnotationSerializer < ActiveModel::Serializer
- attributes :id, :annotation_start_date,:annotation_end_date, :annotation_title, :annotation_description, :isGlobal, :isPop, :user_id, :subject_id
- has_one :user
- has_one :subject
-end
+class CalendarAnnotationSerializer < ActiveModel::Serializer
+ attributes :id, :annotation_start_date,:annotation_end_date, :annotation_title, :annotation_description, :isGlobal, :isPop, :user_id, :subject_id
+ has_one :user
+ has_one :subject
+end
diff --git a/backend/eduapp_db/app/serializers/chat_base_serializer.rb b/backend/eduapp_db/app/serializers/chat_base_serializer.rb
index 779a444d..71a25f73 100644
--- a/backend/eduapp_db/app/serializers/chat_base_serializer.rb
+++ b/backend/eduapp_db/app/serializers/chat_base_serializer.rb
@@ -1,3 +1,3 @@
-class ChatBaseSerializer < ActiveModel::Serializer
- attributes :id, :chat_name, :isGroup, :isReadOnly, :private_key, :public_key
-end
+class ChatBaseSerializer < ActiveModel::Serializer
+ attributes :id, :chat_name, :isGroup, :isReadOnly, :private_key, :public_key
+end
diff --git a/backend/eduapp_db/app/serializers/chat_message_serializer.rb b/backend/eduapp_db/app/serializers/chat_message_serializer.rb
index 58fe1beb..36f8ba22 100644
--- a/backend/eduapp_db/app/serializers/chat_message_serializer.rb
+++ b/backend/eduapp_db/app/serializers/chat_message_serializer.rb
@@ -1,5 +1,5 @@
-class ChatMessageSerializer < ActiveModel::Serializer
- attributes :id, :message, :send_date
- has_one :chat_base
- has_one :user
-end
+class ChatMessageSerializer < ActiveModel::Serializer
+ attributes :id, :message, :send_date
+ has_one :chat_base
+ has_one :user
+end
diff --git a/backend/eduapp_db/app/serializers/chat_participant_serializer.rb b/backend/eduapp_db/app/serializers/chat_participant_serializer.rb
index 66eaea96..e8516da8 100644
--- a/backend/eduapp_db/app/serializers/chat_participant_serializer.rb
+++ b/backend/eduapp_db/app/serializers/chat_participant_serializer.rb
@@ -1,5 +1,5 @@
-class ChatParticipantSerializer < ActiveModel::Serializer
- attributes :id, :isChatAdmin
- has_one :chat_base
- has_one :user
-end
+class ChatParticipantSerializer < ActiveModel::Serializer
+ attributes :id, :isChatAdmin
+ has_one :chat_base
+ has_one :user
+end
diff --git a/backend/eduapp_db/app/serializers/course_serializer.rb b/backend/eduapp_db/app/serializers/course_serializer.rb
index c3ed3e17..42bc848e 100644
--- a/backend/eduapp_db/app/serializers/course_serializer.rb
+++ b/backend/eduapp_db/app/serializers/course_serializer.rb
@@ -1,4 +1,4 @@
-class CourseSerializer < ActiveModel::Serializer
- attributes :id, :name, :institution_id
- has_one :institution
-end
+class CourseSerializer < ActiveModel::Serializer
+ attributes :id, :name, :institution_id
+ has_one :institution
+end
diff --git a/backend/eduapp_db/app/serializers/eduapp_user_session_serializer.rb b/backend/eduapp_db/app/serializers/eduapp_user_session_serializer.rb
index 4c19f6bc..b3d2b349 100644
--- a/backend/eduapp_db/app/serializers/eduapp_user_session_serializer.rb
+++ b/backend/eduapp_db/app/serializers/eduapp_user_session_serializer.rb
@@ -1,4 +1,4 @@
-class EduappUserSessionSerializer < ActiveModel::Serializer
- attributes :id, :session_name, :session_start_date, :session_end_date, :streaming_platform, :resources_platform, :session_chat_id, :batch_id
- has_one :subject
-end
+class EduappUserSessionSerializer < ActiveModel::Serializer
+ attributes :id, :session_name, :session_start_date, :session_end_date, :streaming_platform, :resources_platform, :session_chat_id, :batch_id
+ has_one :subject
+end
diff --git a/backend/eduapp_db/app/serializers/institution_serializer.rb b/backend/eduapp_db/app/serializers/institution_serializer.rb
index 87c71093..8ceca8a5 100644
--- a/backend/eduapp_db/app/serializers/institution_serializer.rb
+++ b/backend/eduapp_db/app/serializers/institution_serializer.rb
@@ -1,3 +1,3 @@
-class InstitutionSerializer < ActiveModel::Serializer
- attributes :id, :name
-end
+class InstitutionSerializer < ActiveModel::Serializer
+ attributes :id, :name
+end
diff --git a/backend/eduapp_db/app/serializers/push_notification_serializer.rb b/backend/eduapp_db/app/serializers/push_notification_serializer.rb
new file mode 100644
index 00000000..35b2cf9b
--- /dev/null
+++ b/backend/eduapp_db/app/serializers/push_notification_serializer.rb
@@ -0,0 +1,3 @@
+class PushNoticationSerializer < ActiveModel::Serializer
+ attributes :id, :endpoint, :user_id, :p256dh, :auth
+end
diff --git a/backend/eduapp_db/app/serializers/resource_serializer.rb b/backend/eduapp_db/app/serializers/resource_serializer.rb
index b6e4ccb1..138a7a64 100644
--- a/backend/eduapp_db/app/serializers/resource_serializer.rb
+++ b/backend/eduapp_db/app/serializers/resource_serializer.rb
@@ -1,5 +1,5 @@
-class ResourceSerializer < ActiveModel::Serializer
- attributes :id, :name, :description, :resource_files, :resource_files_json, :created_at, :updated_at
- has_one :subject
- has_one :user
-end
+class ResourceSerializer < ActiveModel::Serializer
+ attributes :id, :name, :description, :resource_files, :resource_files_json, :created_at, :updated_at
+ has_one :subject
+ has_one :user
+end
diff --git a/backend/eduapp_db/app/serializers/subject_serializer.rb b/backend/eduapp_db/app/serializers/subject_serializer.rb
index 8e675f0a..b38cbe49 100644
--- a/backend/eduapp_db/app/serializers/subject_serializer.rb
+++ b/backend/eduapp_db/app/serializers/subject_serializer.rb
@@ -1,4 +1,5 @@
-class SubjectSerializer < ActiveModel::Serializer
- attributes :id,:subject_code, :name, :description, :color, :course_id
- has_one :course
-end
+class SubjectSerializer < ActiveModel::Serializer
+ attributes :id,:subject_code, :name, :description, :color, :course_id, :chat_link, :users
+ has_one :course
+ has_many :users
+end
diff --git a/backend/eduapp_db/app/serializers/tuition_serializer.rb b/backend/eduapp_db/app/serializers/tuition_serializer.rb
index d8470a06..edd281a7 100644
--- a/backend/eduapp_db/app/serializers/tuition_serializer.rb
+++ b/backend/eduapp_db/app/serializers/tuition_serializer.rb
@@ -1,5 +1,5 @@
-class TuitionSerializer < ActiveModel::Serializer
- attributes :id, :course_id, :user_id
- has_one :course
- has_one :user
-end
+class TuitionSerializer < ActiveModel::Serializer
+ attributes :id, :course_id, :user_id
+ has_one :course
+ has_one :user
+end
diff --git a/backend/eduapp_db/app/serializers/user_info_serializer.rb b/backend/eduapp_db/app/serializers/user_info_serializer.rb
index 1d653709..9ba3a8da 100644
--- a/backend/eduapp_db/app/serializers/user_info_serializer.rb
+++ b/backend/eduapp_db/app/serializers/user_info_serializer.rb
@@ -1,5 +1,5 @@
-class UserInfoSerializer < ActiveModel::Serializer
- attributes :id, :user_name, :profile_image, :teaching_list,:calendar_event, :googleid, :isLoggedWithGoogle
- has_one :user_role
- has_one :user
-end
+class UserInfoSerializer < ActiveModel::Serializer
+ attributes :id, :user_name, :profile_image, :teaching_list,:calendar_event, :googleid, :isLoggedWithGoogle
+ has_one :user_role
+ has_one :user
+end
diff --git a/backend/eduapp_db/app/serializers/user_role_serializer.rb b/backend/eduapp_db/app/serializers/user_role_serializer.rb
index bffcd56f..077faf3f 100644
--- a/backend/eduapp_db/app/serializers/user_role_serializer.rb
+++ b/backend/eduapp_db/app/serializers/user_role_serializer.rb
@@ -1,3 +1,3 @@
-class UserRoleSerializer < ActiveModel::Serializer
- attributes :id, :name, :description, :perms_institution, :perms_course, :perms_subjects, :perms_resources, :perms_sessions, :perms_events, :perms_teachers, :perms_users, :perms_roles, :perms_tuitions, :perms_jti_matchlist, :perms_chat, :perms_chat_participants, :perms_message, :perms_app_views
-end
+class UserRoleSerializer < ActiveModel::Serializer
+ attributes :id, :name, :description, :perms_institution, :perms_course, :perms_subjects, :perms_resources, :perms_sessions, :perms_events, :perms_teachers, :perms_users, :perms_roles, :perms_tuitions, :perms_jti_matchlist, :perms_chat, :perms_chat_participants, :perms_message, :perms_app_views
+end
diff --git a/backend/eduapp_db/app/serializers/user_serializer.rb b/backend/eduapp_db/app/serializers/user_serializer.rb
new file mode 100644
index 00000000..2ec21e8b
--- /dev/null
+++ b/backend/eduapp_db/app/serializers/user_serializer.rb
@@ -0,0 +1,5 @@
+class UserSerializer < ActiveModel::Serializer
+ attributes :confirmation_code, :confirmation_code_exp_time, :created_at, :email, :encrypted_googleid, :extra_fields, :id, :name, :surname, :updated_at, :username, :user_info
+ has_one :user_info
+ has_many :subjects
+end
diff --git a/backend/eduapp_db/app/uploaders/profile_image_uploader.rb b/backend/eduapp_db/app/uploaders/profile_image_uploader.rb
new file mode 100644
index 00000000..402e20fc
--- /dev/null
+++ b/backend/eduapp_db/app/uploaders/profile_image_uploader.rb
@@ -0,0 +1,33 @@
+class ProfileImageUploader < CarrierWave::Uploader::Base
+ include CarrierWave::MiniMagick
+
+ # process resize_to_fit: [200, 200]
+
+ # version :thumb do
+ # process resize_to_fill: [80,80]
+ # end
+
+ # Choose what kind of storage to use for this uploader:
+ storage :file
+ # storage :fog
+
+ # Override the directory where uploaded files will be stored.
+ # This is a sensible default for uploaders that are meant to be mounted:
+ def store_dir
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
+ end
+
+ # Process files as they are uploaded:
+ # process scale: [200, 300]
+ # Add an allowlist of extensions which are allowed to be uploaded.
+ # For images you might use something like this:
+ def extension_allowlist
+ %w(jpg jpeg gif png)
+ end
+
+ # Override the filename of the uploaded files:
+ # Avoid using model.id or version_name here, see uploader/store.rb for details.
+ # def filename
+ # "something.jpg" if original_filename
+ # end
+end
diff --git a/backend/eduapp_db/app/views/devise/confirmations/new.html.erb b/backend/eduapp_db/app/views/devise/confirmations/new.html.erb
index b12dd0cb..b9bed0ec 100644
--- a/backend/eduapp_db/app/views/devise/confirmations/new.html.erb
+++ b/backend/eduapp_db/app/views/devise/confirmations/new.html.erb
@@ -1,16 +1,16 @@
-
- <%= f.label :current_password %> (we need your current password to confirm your changes)
- <%= f.password_field :current_password, autocomplete: "current-password" %>
-
-
-
- <%= f.submit "Update" %>
-
-<% end %>
-
-
Cancel my account
-
-
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
+ <%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password, autocomplete: "current-password" %>
+
+
+
+ <%= f.submit "Update" %>
+
+<% end %>
+
+
Cancel my account
+
+
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
- );
-}
+import "./StandarModal.css";
+
+/**
+ * A custom modal used across the app with many function to provide
+ * the most versatility for any use case possible.
+ *
+ * @param {String} text The text to display in the alert.
+ * @param {String} type The type of icon to display (shown below).
+ * @param {Boolean} show To show the alert or not.
+ * @param {Boolean} iconFill If the icon should be filled.
+ * @param {String} iconColor The color of the icon.
+ * @param {Boolean} isQuestion Displays yes or no instead of okay.
+ * @param {String} customOkay Custom text for Okay.
+ * @param {String} customYes Custom text for Yes.
+ * @param {String} customNo Custom text for No.
+ * @param {Function} onYesAction What to do on Yes.
+ * @param {Function} onNoAction What to do on No.
+ * @param {Function} onCloseAction What to do on Close.
+ * @param {Boolean} hasTransition If the alert has a initial transition.
+ * @param {Boolean} hasIconAnimation If the icon has an appearing animation.
+ * @param {Boolean} showLoader Replaces any buttons for a loader.
+ * @param {HTMLFormElement} form A form element to use forms in the alert.
+ * @param {Boolean} isModalExtraFields Adds custom styling when dealing with extra fields.
+ */
+export default function StandardModal({
+ text,
+ type,
+ show,
+ iconFill,
+ iconColor,
+ isQuestion,
+ onYesAction,
+ onNoAction,
+ onCloseAction,
+ hasTransition,
+ hasIconAnimation,
+ showLoader,
+ form,
+ customOkay,
+ customYes,
+ customNo,
+ isModalExtraFields,
+}) {
+ iconFill = localStorage.darkMode === "1" ? true : iconFill || false;
+ // TYPES = ['success', 'error', 'warning', 'info']
+ return (
+