diff --git a/Frontend Angular 4/src/app/layout/grupos/grupos.component.html b/Frontend Angular 4/src/app/layout/grupos/grupos.component.html
index ceb2c6c2b22382839648bdf0e892e23be96ff47a..eb4a69e437facc755d9b6405541822345d7e78cc 100755
--- a/Frontend Angular 4/src/app/layout/grupos/grupos.component.html	
+++ b/Frontend Angular 4/src/app/layout/grupos/grupos.component.html	
@@ -13,8 +13,20 @@
   <div class="row" style="margin-top: 20px">
     <div class="col-lg-5">
       <div class="card" *ngIf="grupoSeleccionado == undefined">
-        <div class="card-header">
+        <div class="card-header flex justify-between">
           <div *ngIf="grupoSeleccionado == undefined">Grupos</div>
+          <button
+            ngbPopover="{{ 'i18n.action.new' | translate | titleCase }}"
+            triggers="mouseenter:mouseleave"
+            placement="bottom"
+            type="button"
+            class="btn btn-sm btn-secondary"
+            aria-haspopup="true"
+            aria-expanded="false"
+            (click)="openCreateGroupModal(false)"
+          >
+            <i aria-hidden="true" class="fa fa-plus"></i>
+          </button>
         </div>
         <div class="card-block" *ngIf="grupoSeleccionado == undefined">
           <div
@@ -34,7 +46,7 @@
             >
               <i class="fa fa-users matefun-fa-user" aria-hidden="true"></i>
               <p>
-                {{ grupo.grado + "°" + grupo.grupo + " - " + grupo.anio }}
+                {{ grupo.name }}
               </p>
             </div>
           </div>
@@ -48,7 +60,7 @@
         [destroyOnHide]="false"
       >
         <li [ngbNavItem]="1">
-          <a ngbNavLink>Alumnos</a>
+          <a ngbNavLink>Users</a>
           <ng-template ngbNavContent>
             <div class="card">
               <div>
@@ -64,17 +76,36 @@
                 >
                   <i class="fa fa-arrow-up"></i>
                 </button>
+                <button
+                  *ngIf="roleCanManageUsers()"
+                  class="btn btn-sm btn-secondary pull-right"
+                  style="cursor: pointer; margin-top: -35px; margin-right: 36px"
+                  (click)="openManageGroupUsersModal()"
+                  ngbPopover="{{
+                    'i18n.msg.group.manageGroupUsers' | translate | titleCase
+                  }}"
+                  placement="bottom"
+                  triggers="mouseenter:mouseleave"
+                >
+                  <i class="fa fa-users"></i>
+                </button>
+                <button
+                  class="btn btn-sm btn-secondary pull-right"
+                  style="cursor: pointer; margin-top: -35px; margin-right: 71px"
+                  (click)="openDestroyGroupModal()"
+                  ngbPopover="{{
+                    'i18n.msg.group.destroyGroupTooltip' | translate | titleCase
+                  }}"
+                  placement="bottom"
+                  triggers="mouseenter:mouseleave"
+                >
+                  <i class="fa fa-close"></i>
+                </button>
                 <p
                   class="pull-right"
-                  style="margin-top: -34px; margin-right: 60px"
+                  style="margin-top: -34px; margin-right: 128px"
                 >
-                  {{
-                    grupoSeleccionado.grado +
-                      "°" +
-                      grupoSeleccionado.grupo +
-                      " - " +
-                      grupoSeleccionado.anio
-                  }}
+                  {{ grupoSeleccionado.name }}
                 </p>
               </div>
               <div class="card-block">
@@ -83,8 +114,8 @@
                   style="min-height: 100px; overflow-y: scroll"
                 >
                   <div
-                    *ngFor="let alumno of grupoSeleccionado.alumnos"
-                    (click)="seleccionarAlumno(alumno)"
+                    *ngFor="let user of grupoSeleccionado.users"
+                    (click)="seleccionarUser(user)"
                     class="col-sm-3 matefun-group-wrapper"
                   >
                     <i
@@ -92,7 +123,7 @@
                       aria-hidden="true"
                     ></i>
                     <p>
-                      {{ alumno.apellido + ", " + alumno.nombre }}
+                      {{ user.username }}
                     </p>
                   </div>
                 </div>
@@ -104,11 +135,11 @@
           <a ngbNavLink>Archivos</a>
           <ng-template ngbNavContent>
             <div class="card">
-              <div>
+              <div class="relative pull-right right-0">
                 <button
                   class="btn btn-sm btn-secondary pull-right"
                   style="cursor: pointer; margin-top: -35px; margin-right: 1px"
-                  (click)="desseleccionarGrupo()"
+                  (click)="navBack()"
                   ngbPopover="{{
                     'i18n.action.goBack' | translate | titleCase
                   }}"
@@ -117,17 +148,33 @@
                 >
                   <i class="fa fa-arrow-up"></i>
                 </button>
+                <button
+                  ngbPopover="{{ 'i18n.action.new' | translate | titleCase }}"
+                  triggers="mouseenter:mouseleave"
+                  placement="bottom"
+                  type="button"
+                  data-toggle="dropdown"
+                  class="btn btn-sm btn-secondary pull-right"
+                  style="cursor: pointer; margin-top: -35px; margin-right: 36px"
+                  aria-haspopup="true"
+                  aria-expanded="false"
+                >
+                  <i aria-hidden="true" class="fa fa-plus"></i>
+                </button>
+                <div class="dropdown-menu right-0" style="left: unset">
+                  <a class="dropdown-item" (click)="mkFile(true)">
+                    {{ "i18n.object.file" | translate | titleCase }}
+                  </a>
+                  <div role="separator" class="dropdown-divider"></div>
+                  <a class="dropdown-item" (click)="mkFile(false)">
+                    {{ "i18n.object.folder" | translate | titleCase }}
+                  </a>
+                </div>
                 <p
                   class="pull-right"
-                  style="margin-top: -34px; margin-right: 60px"
+                  style="margin-top: -34px; margin-right: 95px"
                 >
-                  {{
-                    grupoSeleccionado.grado +
-                      "°" +
-                      grupoSeleccionado.grupo +
-                      " - " +
-                      grupoSeleccionado.anio
-                  }}
+                  {{ grupoSeleccionado.name }}
                 </p>
               </div>
               <div class="card-block">
@@ -136,12 +183,19 @@
                   style="min-height: 100px; overflow-y: scroll"
                 >
                   <div
-                    *ngFor="let archivo of grupoSeleccionado.archivos"
+                    *ngFor="let archivo of directorioActual.archivos"
                     (click)="seleccionarArchivo(archivo)"
                     class="col-sm-3 col-4 matefun-group-wrapper"
                   >
                     <i
+                      *ngIf="archivo.directorio"
+                      class="fa fa-folder matefun-fa-folder"
+                      aria-hidden="true"
+                    ></i>
+                    <i
+                      *ngIf="!archivo.directorio"
                       class="fa fa-file-text matefun-fa-file"
+                      [class.text-blue-400]="archivo.feedbackRequested"
                       aria-hidden="true"
                     ></i>
                     <p>{{ archivo.nombre }}</p>
@@ -156,14 +210,14 @@
       <div [ngbNavOutlet]="nav" class="mt-2" *ngIf="grupoSeleccionado"></div>
     </div>
     <div class="col-lg-7">
-      <div class="card" *ngIf="alumnoSeleccionado">
+      <div class="card" *ngIf="selectedUser && !archivoSeleccionado">
         <div class="card-block">
           <div
             class="row listadoEntregasAlumnoGrupos"
             style="min-height: 100px; overflow-y: scroll"
           >
             <div
-              *ngFor="let entrega of alumnoSeleccionado.archivos"
+              *ngFor="let entrega of selectedUserDirectorioActual"
               (click)="seleccionarEntrega(entrega)"
               class="col-sm-3 col-4 matefun-file-wrapper"
             >
@@ -175,7 +229,7 @@
               <p>{{ entrega.nombre }}</p>
             </div>
             <div
-              *ngIf="alumnoSeleccionado.archivos.length == 0"
+              *ngIf="selectedUser && selectedUserDirectorioActual.length == 0"
               style="width: 100%; text-align: center"
             >
               <i
@@ -187,10 +241,8 @@
                 class="fa fa-file-text"
               ></i>
               <p>
-                No hay entregas del alumno:
-                {{
-                  alumnoSeleccionado.nombre + " " + alumnoSeleccionado.apellido
-                }}
+                No hay entregas del usuario:
+                {{ selectedUser.username }}
               </p>
             </div>
           </div>
@@ -198,9 +250,7 @@
       </div>
       <div
         class="card"
-        *ngIf="
-          alumnoSeleccionado == undefined && archivoSeleccionado == undefined
-        "
+        *ngIf="selectedUser == undefined && archivoSeleccionado == undefined"
       >
         <div class="card-block">
           <div
@@ -231,14 +281,71 @@
             Calificar
           </button>
           <button
-            *ngIf="esArchivoGrupo()"
-            ngbPopover="Cargar/Editar"
+            ngbPopover="{{ 'i18n.action.load' | translate | titleCase }}/{{
+              'i18n.action.edit' | translate | titleCase
+            }}"
             placement="bottom"
             triggers="mouseenter:mouseleave"
             class="btn btn-sm btn-secondary pull-left mr-2"
-            (click)="cargarArchivoCompartido()"
+            (click)="cargarArchivo()"
           >
-            <i class="fa fa-pencil"></i>
+            <i aria-hidden="true" class="fa fa-pencil"></i>
+          </button>
+          <button
+            ngbPopover="{{ 'i18n.action.delete' | translate | titleCase }}"
+            placement="bottom"
+            triggers="mouseenter:mouseleave"
+            class="btn btn-sm btn-secondary pull-left mr-2"
+            (click)="mostrarEliminarDialogo()"
+          >
+            <i aria-hidden="true" class="fa fa-remove"></i>
+          </button>
+          <button
+            ngbPopover="{{ 'i18n.action.move' | translate | titleCase }} {{
+              'i18n.object.file' | translate | titleCase
+            }}"
+            placement="bottom"
+            triggers="mouseenter:mouseleave"
+            class="btn btn-sm btn-secondary pull-left mr-2"
+            (click)="seleccionarDirectorioAMover()"
+          >
+            <i aria-hidden="true" class="fa fa-cut"></i>
+          </button>
+          <button
+            *ngIf="canRequestFeedback()"
+            ngbPopover="{{
+              'i18n.action.requestFeedback' | translate | titleCase
+            }} {{ 'i18n.object.file' | translate | titleCase }}"
+            placement="bottom"
+            triggers="mouseenter:mouseleave"
+            class="btn btn-sm btn-secondary pull-left mr-2"
+            (click)="requestFeedback()"
+          >
+            <i aria-hidden="true" class="fa fa-exchange"></i>
+          </button>
+          <button
+            *ngIf="canAssignFile()"
+            ngbPopover="{{
+              'i18n.action.assignFile' | translate | titleCase
+            }} {{ archivoSeleccionado.nombre }}"
+            placement="bottom"
+            triggers="mouseenter:mouseleave"
+            class="btn btn-sm btn-secondary pull-left mr-2"
+            (click)="openAssignFileModal()"
+          >
+            <i aria-hidden="true" class="fa fa-share"></i>
+          </button>
+          <button
+            *ngIf="canReturnFeedback()"
+            ngbPopover="{{
+              'i18n.action.returnFeedback' | translate | titleCase
+            }} {{ 'i18n.object.file' | translate | titleCase }}"
+            placement="bottom"
+            triggers="mouseenter:mouseleave"
+            class="btn btn-sm btn-secondary pull-left mr-2"
+            (click)="returnFeedback()"
+          >
+            <i aria-hidden="true" class="fa fa-exchange"></i>
           </button>
           <div class="pull-left">
             Nombre: {{ archivoSeleccionado?.nombre }} - Creado:
@@ -274,3 +381,64 @@
   *ngIf="modalQualifyDelivery"
 >
 </matefun-modal-calificar-entrega>
+
+<matefun-modal-nuevo-archivo
+  confirmLabel="{{ 'i18n.action.create' | translate | titleCase }}"
+  fileDescriptionLabel="{{ 'i18n.object.descr' | translate | titleCase }}:"
+  fileNameLabel="{{ 'i18n.object.name' | translate | titleCase }}:"
+  header="{{ 'i18n.action.new' | translate | titleCase }}
+  {{
+    (modalTypeIsFile ? 'i18n.object.file' : 'i18n.object.folder')
+      | translate
+      | titleCase
+  }} "
+  [opened]="modalCreateFileOpened"
+  [typeOfFile]="modalTypeIsFile ? 'file' : 'directory'"
+  (close)="modalCreateFile = false"
+  (confirmFileCreation)="
+    modalTypeIsFile
+      ? confirmDocumentCreation($event)
+      : confirmFileCreation($event)
+  "
+  *ngIf="modalCreateFile"
+>
+</matefun-modal-nuevo-archivo>
+
+<matefun-modal-seleccionar-directorio
+  confirmLabel="{{ 'i18n.action.move' | translate | titleCase }} {{
+    'i18n.object.here' | translate
+  }}"
+  [currentDirectory]="currentDirOfFileToMove"
+  [fileIdToMove]="archivoSeleccionado ? archivoSeleccionado.id : -1"
+  fileNameLabel="{{ 'i18n.object.name' | translate | titleCase }}"
+  header="{{ 'i18n.msg.file.move' | translate }}"
+  [initialPath]="currentPath"
+  navigateBackLabel="{{ 'i18n.action.goBack' | translate | titleCase }}"
+  [opened]="modalMoveFileOpened"
+  type-of-modal="move"
+  (close)="modalMoveFile = false"
+  (confirmFileCreation)="confirmFileMove($event)"
+  (navBack)="navigateBackModal($event)"
+  (navTo)="currentDirOfFileToMove = $event.detail"
+  *ngIf="modalMoveFile"
+>
+</matefun-modal-seleccionar-directorio>
+
+<matefun-modal-borrar-archivo
+  bodyDescription="{{ 'i18n.msg.file.delete' | translate : fileNameToRemove }}"
+  cancelLabel="{{ 'i18n.action.cancel' | translate | titleCase }}"
+  confirmLabel="{{ 'i18n.action.delete' | translate | titleCase }}"
+  header="{{ 'i18n.action.delete' | translate | titleCase }}
+  {{
+    (modalTypeIsFile ? 'i18n.object.file' : 'i18n.object.folder')
+      | translate
+      | titleCase
+  }}"
+  [opened]="modalRemoveFileOpened"
+  [typeOfFile]="modalTypeIsFile ? 'file' : 'directory'"
+  (close)="modalRemoveFile = false"
+  (cancelAction)="modalRemoveFileOpened = false"
+  (removeFile)="confirmFileDeletion()"
+  *ngIf="modalRemoveFile"
+>
+</matefun-modal-borrar-archivo>
diff --git a/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts b/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts
index a41d57e515742ec20ebd45668740d87c0558f17e..45e72b6aeb19ba2d79f0c920aa76f6529cc5ecd9 100755
--- a/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts	
+++ b/Frontend Angular 4/src/app/layout/grupos/grupos.component.ts	
@@ -1,8 +1,12 @@
-import { Component } from "@angular/core";
+import { ChangeDetectorRef, Component } from "@angular/core";
 import { Router } from "@angular/router";
 
-import { Archivo, Evaluacion } from "../../shared/objects/archivo-types";
-import { Grupo } from "../../shared/objects/grupo";
+import {
+  Archivo,
+  Evaluacion,
+  MDocument,
+} from "../../shared/objects/archivo-types";
+import { Group } from "../../shared/objects/grupo";
 import { Usuario } from "../../shared/objects/usuario";
 import { AuthenticationService } from "../../shared/services/authentication.service";
 import { HaskellService } from "../../shared/services/haskell.service";
@@ -10,6 +14,29 @@ import { SessionService } from "../../shared/services/session.service";
 import { NgbPopoverConfig, NgbPopover } from "@ng-bootstrap/ng-bootstrap";
 import { NotificacionService } from "../../shared/services/notificacion.service";
 import { TranslateService } from "@ngx-translate/core";
+import { GroupService } from "../../shared/services/group.service";
+import { GroupFileService } from "../../shared/services/group-file.service";
+import { FileService } from "../../shared/services/file.service";
+import { DocumentService } from "../../shared/services/document.service";
+import { GroupDocumentService } from "../../shared/services/group-document.service";
+import {
+  roleCanManageGroupUsers,
+  roleCanDestroyGroup,
+  findInTree,
+} from "app/utils";
+import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
+import { CreateGroupModal } from "../../shared/components/create-group-modal/create-group-modal.component";
+import { ManageGroupUsersModal } from "app/shared/components/manage-group-users-modal/manage-group-users-modal.component";
+import {
+  DestroyGroupModal,
+  RequestFeedbackModal,
+  ReturnFeedbackModal,
+  AssignFileModal,
+} from "app/shared";
+
+const STARTS_WITH_CAPITAL_LETTER_REGEX = /^[A-Z]/;
+
+const ID_ROOT_DIR = -1;
 
 @Component({
   selector: "grupos",
@@ -17,12 +44,14 @@ import { TranslateService } from "@ngx-translate/core";
 })
 export class GruposComponent {
   archivos: Archivo[] = [];
-  grupos: Grupo[] = [];
-  grupoSeleccionado: Grupo = undefined;
+  selectedUserArchivos: Archivo[] = [];
+  grupos: Group[] = [];
+  grupoSeleccionado: Group = undefined;
 
-  alumnoSeleccionado: Usuario = undefined;
+  selectedUser: Usuario = undefined;
 
   archivoSeleccionado: Archivo = undefined;
+  selectedFile: Archivo = undefined;
 
   tipoArchivo: string = undefined;
 
@@ -33,6 +62,12 @@ export class GruposComponent {
   configCodeMirror = JSON.parse(localStorage.getItem("codeMirrorConfig"));
   translateService: any;
 
+  selectedUserFileArray: any;
+  selectedUserDirectorioActual: any;
+
+  createModalRef: any;
+
+  preview: string = "";
   // - - - - - - - - - - - -  Modal show confirm  - - - - - - - - - - - -
   /**
    * Con `true` se renderiza el modal de calificar entrega.
@@ -60,13 +95,69 @@ export class GruposComponent {
     },
   ];
 
+  // - - - - - - - - - - - - - Modal create file - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de crear un archivo
+   */
+  modalCreateFile = false;
+
+  /**
+   * Con `true` se configura el modal para que se muestre la interfaz de
+   * agregar/borrar archivo. De otro modo, se muestra la interfaz de
+   * agregar/borrar directorio
+   */
+  modalTypeIsFile = true;
+
+  /**
+   * Con `true` se indica que el modal -de crear un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalCreateFileOpened = true;
+
+  /**
+   * Directorio actual sobre el cual será desplegada la lista de directorios
+   * del modal mover archivo.
+   */
+  currentDirOfFileToMove: Archivo;
+
+  /**
+   * Determina la ruta en donde se encuentra ubicado el archivo/directorio
+   * seleccionado actualmente.
+   */
+  currentPath: string = "/";
+
+  // - - - - - - - - - - - - -  Modal move file  - - - - - - - - - - - - -
+  /**
+   * Con `true` se renderiza el modal de mover un archivo
+   */
+  modalMoveFile = false;
+
+  /**
+   * Con `true` se indica que el modal -de mover un archivo- se quiere abrir.
+   * Útil para avisar al modal que anime el dismiss antes de que se elimine del
+   * DOM
+   */
+  modalMoveFileOpened = true;
+
+  fileNameToRemove: { fileName: string } = { fileName: "" };
+  modalRemoveFile = false;
+  modalRemoveFileOpened = true;
+
   constructor(
     private router: Router,
     private authService: AuthenticationService,
     private haskellService: HaskellService,
     private notifService: NotificacionService,
     private sessionService: SessionService,
-    public translate: TranslateService
+    public translate: TranslateService,
+    public groupService: GroupService,
+    public groupFileService: GroupFileService,
+    public documentService: DocumentService,
+    public groupDocumentService: GroupDocumentService,
+    public fileService: FileService,
+    private modalService: NgbModal,
+    private changeDetectorRef: ChangeDetectorRef
   ) {
     this.translateService = translate;
     this.directorioActual = {};
@@ -91,6 +182,12 @@ export class GruposComponent {
 
   ngOnInit() {
     // let cedula = this.authService.getUser().cedula; // cedula
+    this.confirmGroupCreation = this.confirmGroupCreation.bind(this);
+    this.confirmGroupUpdated = this.confirmGroupUpdated.bind(this);
+    this.confirmGroupDestroyed = this.confirmGroupDestroyed.bind(this);
+    this.confirmFeedbackRequsted = this.confirmFeedbackRequsted.bind(this);
+    this.confirmFeedbackReturned = this.confirmFeedbackReturned.bind(this);
+
     this.loading = true;
     // this.haskellService.getGrupos(cedula).subscribe(
     //   (grupos) => {
@@ -100,6 +197,19 @@ export class GruposComponent {
     //   },
     //   (error) => console.log(error)
     // );
+    this.loadGroups();
+  }
+
+  loadGroups(next?: () => void) {
+    this.groupService.getGroups().subscribe(
+      (grupos) => {
+        this.grupos = grupos.groups;
+        // this.ordenarGrupos();
+        this.loading = false;
+        if (next) next();
+      },
+      (error) => console.log(error)
+    );
   }
 
   showNotification(type: "error" | "success" | "warning", traslation: string) {
@@ -116,9 +226,12 @@ export class GruposComponent {
   }
 
   ordenarArchivos() {
-    this.grupoSeleccionado.archivos = this.grupoSeleccionado.archivos.sort(
-      this.ordenarAlph
-    );
+    // var tipo = this.sortFunction;
+    // if (tipo === "tipo") {
+    //   this.ordenarMixto();
+    // } else if (tipo === "fecha") {
+    //   this.ordenarFechaCreacion();
+    // }
   }
 
   //ordeno los archivos del alumno (los archivos entregados.)
@@ -150,51 +263,481 @@ export class GruposComponent {
   }
 
   ordenarAlumnos() {
-    this.grupoSeleccionado.alumnos = this.grupoSeleccionado.alumnos.sort(
-      this.ordenarAlumnosF
-    );
+    // this.grupoSeleccionado.alumnos = this.grupoSeleccionado.alumnos.sort(
+    //   this.ordenarAlumnosF
+    // );
+  }
+
+  /**
+   * Renderiza en pantalla el modal de agregar archivos o directorios,
+   * dependiendo del valor de `modalTypeIsFile`.
+   * @param modalTypeIsFile Con `true` se indica que el modal a renderizar es el de agregar archivo. De otro modo, se renderiza el de agregar directorio.
+   */
+  mkFile(modalTypeIsFile: boolean) {
+    this.modalTypeIsFile = modalTypeIsFile;
+
+    // Mostrar el modal
+    this.modalCreateFile = true;
+    this.modalCreateFileOpened = true;
   }
 
   seleccionarGrupo(grupo) {
     this.grupoSeleccionado = grupo;
     this.ordenarAlumnos();
-    this.ordenarArchivos();
-    this.archivoSeleccionado = undefined;
-    this.alumnoSeleccionado = undefined;
+    this.loadFilesAndFolders(grupo.id);
+    this.selectedUser = undefined;
+  }
+
+  loadFilesAndFolders(grupoId: number, directorioActualId = null) {
+    this.groupFileService.getGroupFiles(grupoId).subscribe(
+      (files) => {
+        this.tree = this.fileService.fileToArchivo(files["files"]);
+
+        this.archivos = [this.tree];
+        this.loading = false;
+
+        if (directorioActualId) {
+          this.directorioActual = findInTree(this.archivos, directorioActualId);
+        } else {
+          this.directorioActual = this.tree;
+        }
+        this.ordenarArchivos();
+        this.sessionService.setArchivosTree(this.tree);
+
+        this.currentDirOfFileToMove = this.directorioActual;
+      },
+      (error) => console.log(error)
+    );
   }
 
   desseleccionarGrupo() {
     this.grupoSeleccionado = undefined;
     this.archivoSeleccionado = undefined;
-    this.alumnoSeleccionado = undefined;
+    this.selectedUser = undefined;
   }
 
-  seleccionarAlumno(alumno) {
-    if (!(typeof alumno === "undefined")) {
-      this.alumnoSeleccionado = alumno;
-      this.ordenarArchivosAlumno();
-      this.archivoSeleccionado = undefined;
+  seleccionarUser(user) {
+    this.groupFileService
+      .getFeedbackRequestedGroupFiles(this.grupoSeleccionado.id, user.id)
+      .subscribe(
+        (files) => {
+          this.selectedUserFileArray = files["files"].map((file) =>
+            this.fileService.fileToArchivo(file)
+          );
+          this.selectedUserArchivos = [this.selectedUserFileArray];
+          this.loading = false;
+
+          this.selectedUserDirectorioActual = this.selectedUserFileArray;
+          this.ordenarArchivos();
+          this.sessionService.setArchivosTree(this.selectedUserFileArray);
+
+          this.selectedUser = user;
+
+          this.archivoSeleccionado = undefined;
+          this.selectedFile = undefined; // Probando
+        },
+        (error) => console.log(error)
+      );
+  }
+
+  canRequestFeedback() {
+    return (
+      !!this.grupoSeleccionado.id &&
+      !!this.selectedFile &&
+      this.selectedFile.feedbackRequested !== undefined &&
+      !this.selectedFile.feedbackRequested
+    );
+  }
+
+  requestFeedback() {
+    this.openRequestFeedbackModal();
+  }
+
+  canReturnFeedback() {
+    return (
+      !!this.grupoSeleccionado &&
+      !!this.selectedFile &&
+      this.selectedFile.feedbackRequested !== undefined &&
+      this.selectedFile.feedbackRequested &&
+      this.groupService.userCanReturnFeedback(this.grupoSeleccionado.role)
+    );
+  }
+
+  returnFeedback() {
+    this.openReturnFeedbackModal();
+  }
+
+  openReturnFeedbackModal() {
+    if (!this.grupoSeleccionado) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    if (!this.selectedFile.fileId) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(ReturnFeedbackModal);
+
+    this.createModalRef.componentInstance.confirmFeedbackReturned =
+      this.confirmFeedbackReturned;
+    this.createModalRef.componentInstance.groupName = null;
+    this.createModalRef.componentInstance.groupId = this.grupoSeleccionado.id;
+    this.createModalRef.componentInstance.fileName = this.selectedFile.nombre;
+    this.createModalRef.componentInstance.fileId = this.selectedFile.fileId;
+    this.createModalRef.componentInstance.userId =
+      this.selectedUser?.id ||
+      JSON.parse(localStorage.getItem("currentUser"))["id"];
+  }
+
+  confirmFeedbackReturned() {
+    if (!!this.selectedUser) {
+      this.selectedFile = null;
+      this.archivoSeleccionado = null;
+      this.seleccionarUser(this.selectedUser);
+    } else {
+      this.loadFilesAndFolders(
+        this.grupoSeleccionado.id,
+        this.directorioActual.id
+      );
     }
   }
 
   seleccionarArchivo(archivo) {
+    this.selectedFile = archivo;
+    if (archivo.directorio) {
+      this.directorioActual = archivo;
+      this.archivoSeleccionado = undefined;
+      this.selectedFile = undefined; // Probando
+      this.archivoSeleccionado = archivo;
+      this.currentPath += `${archivo.nombre}/`;
+      this.preview = "";
+    } else {
+      this.selectedUser = undefined;
+      this.tipoArchivo = "compartido";
+      this.groupDocumentService
+        .getGroupDocument(
+          this.grupoSeleccionado.id,
+          archivo.documentId,
+          this.selectedUser?.id
+        )
+        .subscribe(
+          (data) => {
+            const document = data["document"];
+            const archivoDocument =
+              this.documentService.documentToArchivo(document);
+            this.actualizarArchivoSeleccionado(archivoDocument);
+          },
+          (error) => console.log(error)
+        );
+    }
+  }
+
+  /**
+   * Actualiza el estado del archivo seleccionado, así como la preview del
+   * contenido de dicho archivo.
+   * @param archivo Archivo a seleccionar
+   */
+  actualizarArchivoSeleccionado(archivo: Archivo) {
+    if (!!this.selectedFile) {
+      archivo.feedbackRequested = this.selectedFile.feedbackRequested;
+    }
     this.archivoSeleccionado = archivo;
-    this.alumnoSeleccionado = undefined;
-    this.tipoArchivo = "compartido";
+    this.selectedFile = archivo;
+    this.preview = !!archivo?.contenido ? archivo.contenido : "";
+  }
+
+  /**
+   * Navega hacia el directorio padre en la vista principal de directorios.
+   * @param shouldUpdateSelectedFile Determina si se debe actualizar el archivo seleccionado cuando se navega hacia atrás
+   */
+  navBack(shouldUpdateSelectedFile = true) {
+    const { padreId } = this.directorioActual;
+
+    if (padreId === ID_ROOT_DIR) {
+      return;
+    }
+
+    // Actualiza el current path
+    const lastDirectoryIndex = this.currentPath.lastIndexOf(
+      `${this.directorioActual.nombre}`
+    );
+
+    this.currentPath = this.currentPath.substring(0, lastDirectoryIndex);
+
+    const padre = findInTree(this.archivos, padreId);
+
+    if (shouldUpdateSelectedFile) {
+      // Cuando se selecciona un directorio cuyo id es el root, significa que ese
+      // es el último archivo de la rama de directorios. En otras palabras, el
+      // root se identifica porque su padreId es ID_ROOT_DIR.
+      const archivoSeleccionado =
+        padre.padreId == ID_ROOT_DIR ? undefined : padre;
+      this.actualizarArchivoSeleccionado(archivoSeleccionado);
+    }
+
+    // Actualiza la vista de directorios y archivos
+    this.directorioActual = padre;
   }
 
   seleccionarEntrega(entrega) {
-    this.archivoSeleccionado = entrega;
-    this.alumnoSeleccionado = undefined;
+    this.groupDocumentService
+      .getGroupDocument(
+        this.grupoSeleccionado.id,
+        entrega.documentId,
+        this.selectedUser.id
+      )
+      .subscribe(
+        (data) => {
+          // this.archivoSeleccionado = entrega;
+          const document = data["document"];
+          const archivoDocument =
+            this.documentService.documentToArchivo(document);
+          archivoDocument.feedbackRequested = true;
+          this.actualizarArchivoSeleccionado(archivoDocument);
+        },
+        (error) => console.log(error)
+      );
+    // this.selectedUser = undefined;
     this.tipoArchivo = "entrega";
   }
 
+  roleCanManageUsers(): boolean {
+    return (
+      !!this.grupoSeleccionado &&
+      roleCanManageGroupUsers(this.grupoSeleccionado.role)
+    );
+  }
+
+  roleCanDestroyGroup(): boolean {
+    return (
+      !!this.grupoSeleccionado &&
+      roleCanDestroyGroup(this.grupoSeleccionado.role)
+    );
+  }
+
+  openRequestFeedbackModal() {
+    if (!this.grupoSeleccionado.id) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    if (!this.selectedFile.id) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(RequestFeedbackModal);
+
+    this.createModalRef.componentInstance.groupName =
+      this.grupoSeleccionado.name;
+    this.createModalRef.componentInstance.groupId = this.grupoSeleccionado.id;
+    this.createModalRef.componentInstance.fileName =
+      this.archivoSeleccionado.nombre;
+    this.createModalRef.componentInstance.fileId =
+      this.archivoSeleccionado.fileId;
+    this.createModalRef.componentInstance.confirmFeedbackRequested =
+      this.confirmFeedbackRequsted;
+  }
+
+  confirmFeedbackRequsted() {
+    this.archivoSeleccionado.feedbackRequested = true;
+    this.selectedFile.feedbackRequested = true;
+    const fileInDirectory = this.directorioActual.archivos.find(
+      (archivo) => archivo.documentId === this.archivoSeleccionado.id
+    );
+    if (!!fileInDirectory) {
+      fileInDirectory.feedbackRequested = true;
+    }
+    this.changeDetectorRef.detectChanges();
+  }
+
+  mostrarEliminarDialogo() {
+    // Chequear si se seleccionó un archivo
+    if (!this.archivoSeleccionado) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.fileNameToRemove = {
+      fileName: this.archivoSeleccionado?.nombre || this.selectedFile?.nombre,
+    };
+
+    // Determina el tipo de modal a renderizar
+    this.modalTypeIsFile = !this.archivoSeleccionado.directorio;
+
+    // Mostrar el modal
+    this.modalRemoveFile = true;
+    this.modalRemoveFileOpened = true;
+  }
+
+  confirmFileDeletion() {
+    let fileIdToDelete = null;
+    let navBack = false;
+    if (this.archivoSeleccionado?.fileId) {
+      fileIdToDelete = this.archivoSeleccionado.fileId;
+    } else if (this.selectedFile?.fileId) {
+      fileIdToDelete = this.selectedFile.fileId;
+    } else if (this.archivoSeleccionado?.id) {
+      fileIdToDelete = this.archivoSeleccionado.id;
+      navBack = true;
+    }
+
+    this.groupFileService
+      .deleteGroupFile(
+        this.grupoSeleccionado.id,
+        this.archivoSeleccionado?.fileId ||
+          this.selectedFile?.fileId ||
+          this.archivoSeleccionado?.id
+      )
+      .subscribe(
+        (_) => {
+          this.modalRemoveFileOpened = false;
+          if (navBack) {
+            this.navBack();
+          }
+          this.loadFilesAndFolders(
+            this.grupoSeleccionado.id,
+            this.directorioActual.id
+          );
+        },
+        (error) => console.log(error)
+      );
+  }
+
+  openDestroyGroupModal() {
+    if (!this.grupoSeleccionado) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(DestroyGroupModal);
+
+    this.createModalRef.componentInstance.groupName =
+      this.grupoSeleccionado.name;
+    this.createModalRef.componentInstance.groupId = this.grupoSeleccionado.id;
+    this.createModalRef.componentInstance.confirmGroupDestroyed =
+      this.confirmGroupDestroyed;
+    this.createModalRef.componentInstance.userRole =
+      this.grupoSeleccionado.role;
+
+    // this.translateService
+    //   .get("i18n.warning.group.destroy", {
+    //     group: this.grupoSeleccionado.name,
+    //   })
+    //   .subscribe((res) => {
+    //     if (confirm(res)) {
+    //       this.groupService.destroyGroup(this.grupoSeleccionado.id).subscribe(
+    //         (data) => {
+    //           this.loadGroups();
+    //           this.grupoSeleccionado = undefined;
+    //         },
+    //         (error) => {
+    //           this.notifService.error(error);
+    //         }
+    //       );
+  }
+
+  openAssignFileModal() {
+    if (!this.grupoSeleccionado) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    if (!this.selectedFile.fileId) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(AssignFileModal);
+
+    this.createModalRef.componentInstance.groupName = null;
+    this.createModalRef.componentInstance.groupId = this.grupoSeleccionado.id;
+    this.createModalRef.componentInstance.fileName = this.selectedFile.nombre;
+    this.createModalRef.componentInstance.fileId = this.selectedFile.fileId;
+    this.createModalRef.componentInstance.users = this.grupoSeleccionado.users;
+    this.createModalRef.componentInstance.userFilter = "role";
+    this.createModalRef.componentInstance.confirmFileAssigned =
+      this.confirmFileAssigned;
+  }
+
+  confirmFileAssigned() {}
+
+  canAssignFile() {
+    return (
+      !!this.grupoSeleccionado &&
+      !!this.selectedFile &&
+      !this.selectedUser &&
+      this.groupService.userCanAssignFiles(this.grupoSeleccionado.role)
+    );
+  }
+
+  confirmGroupDestroyed() {
+    this.desseleccionarGrupo();
+    this.loadGroups();
+  }
+
   mostrarModalCalificarEntrega() {
     // Mostrar el modal
     this.modalQualifyDelivery = true;
     this.modalQualifyDeliveryOpened = true;
   }
 
+  openCreateGroupModal() {
+    this.createModalRef = this.modalService.open(CreateGroupModal);
+
+    this.createModalRef.componentInstance.modalTitle = "Nuevo Grupo";
+    this.createModalRef.componentInstance.confirmGroupCreation =
+      this.confirmGroupCreation;
+  }
+
+  confirmGroupCreation(nombre: string) {
+    if (nombre == undefined || nombre == "") {
+      this.showNotification("error", "i18n.warning.group.invalidName");
+      return;
+    }
+
+    /** Expresión regular para chequear que el nombre esté empiece con mayúscula */
+    var regex = /^[A-Z]/;
+    if (!regex.test(nombre)) {
+      this.showNotification("error", "i18n.warning.group.capitalLetter");
+      return;
+    }
+
+    this.groupService.createGroup(nombre).subscribe(
+      (data) => {
+        this.loadGroups();
+
+        this.grupoSeleccionado = data.body["group"];
+        this.createModalRef.close();
+      },
+      (error) => {
+        this.notifService.error(error);
+      }
+    );
+  }
+
+  confirmGroupUpdated() {
+    this.loadGroups(() => {
+      this.grupoSeleccionado = this.grupos.find(
+        (grupo) => grupo.id == this.grupoSeleccionado.id
+      );
+    });
+  }
+
+  openManageGroupUsersModal() {
+    this.createModalRef = this.modalService.open(ManageGroupUsersModal);
+
+    this.createModalRef.componentInstance.modalTitle =
+      "Administrar usuarios del grupo";
+    this.createModalRef.componentInstance.groupName =
+      this.grupoSeleccionado.name;
+    this.createModalRef.componentInstance.groupId = this.grupoSeleccionado.id;
+    this.createModalRef.componentInstance.confirmGroupUpdated =
+      this.confirmGroupUpdated;
+  }
+
   confirmFileQualify(event: CustomEvent<any>) {
     const { descripcion, estado, nota } = event.detail;
 
@@ -234,25 +777,142 @@ export class GruposComponent {
   }
 
   esArchivoGrupo() {
-    if (
-      this.archivoSeleccionado &&
-      this.grupoSeleccionado &&
-      this.grupoSeleccionado.archivos.some(
-        (arch) => arch.id == this.archivoSeleccionado.id
-      )
-    ) {
-      return true;
-    } else {
-      return false;
-    }
+    // if (
+    //   this.archivoSeleccionado &&
+    //   this.grupoSeleccionado &&
+    //   this.grupoSeleccionado.archivos.some(
+    //     (arch) => arch.id == this.archivoSeleccionado.id
+    //   )
+    // ) {
+    //   return true;
+    // } else {
+    //   return false;
+    // }
+    return true;
   }
 
-  cargarArchivoCompartido() {
+  cargarArchivo() {
     if (!this.archivoSeleccionado || this.archivoSeleccionado.directorio) {
       this.showNotification("warning", "i18n.warning.file.noSelected");
       return;
     }
     this.sessionService.setArchivo(this.archivoSeleccionado);
-    this.router.navigate(["/matefun"]);
+    const userId = !!this.selectedUser
+      ? this.selectedUser.id
+      : JSON.parse(localStorage.getItem("currentUser"))["id"];
+
+    this.router.navigate([
+      `/grupos/${this.grupoSeleccionado.id}/users/${userId}/matefun/${this.archivoSeleccionado.id}`,
+    ]);
+  }
+
+  seleccionarDirectorioAMover() {
+    if (!this.archivoSeleccionado) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    // Si el archivo es del alumno, se puede mover.
+    // No se controla por creador, dado que los compartidos mantienen este atributo
+    // if (!this.archivos.some((arch) => arch.id == this.archivoSeleccionado.id)) {
+    //   this.showNotification("warning", "i18n.warning.file.noPermissionMove");
+    //   return;
+    // }
+
+    // this.navBack(false);
+    if (this.archivoSeleccionado.directorio) {
+      this.currentDirOfFileToMove = this.directorioActual.parent;
+    } else {
+      this.currentDirOfFileToMove = this.directorioActual;
+    }
+
+    // Mostrar el modal
+    this.modalMoveFile = true;
+    this.modalMoveFileOpened = true;
+  }
+
+  /**
+   * Valida y confirma la creación del archivo.
+   * @param event Evento devuelto por el modal asociado para crear el archivo. En el detalle contiene el `nombre` y `descripcion` del archivo que se desea agregar.
+   */
+  confirmFileCreation(event: CustomEvent) {
+    const { nombre, descripcion } = event.detail;
+
+    // Antes que nada, se chequea que empiece con mayúscula
+    if (!STARTS_WITH_CAPITAL_LETTER_REGEX.test(nombre)) {
+      this.showNotification("warning", "i18n.warning.file.capitalLetter");
+      return;
+    }
+
+    const archivo = new Archivo();
+    // archivo.cedulaCreador = this.directorioActual.cedulaCreador; // cedula
+    archivo.contenido = this.modalTypeIsFile ? "" : descripcion || "";
+    archivo.directorio = !this.modalTypeIsFile;
+    archivo.editable = true;
+    archivo.fechaCreacion = new Date();
+    archivo.nombre = nombre;
+    archivo.padreId = this.directorioActual.id;
+    archivo.archivos = [];
+
+    const that = this;
+    const idDirectorioActual = this.directorioActual.id;
+
+    const file = this.fileService.archivoToFile(archivo);
+    this.groupFileService
+      .createGroupFile(this.grupoSeleccionado.id, file)
+      .subscribe(
+        () => {
+          that.loadFilesAndFolders(idDirectorioActual);
+
+          // Cerrar el modal en caso de éxito
+          that.modalCreateFileOpened = false;
+        },
+        (error) => {
+          that.notifService.error(error.text());
+
+          // Cerrar el modal en caso de error
+          that.modalCreateFileOpened = false;
+        }
+      );
+  }
+
+  /**
+   * Valida y confirma la creación del archivo.
+   * @param event Evento devuelto por el modal asociado para crear el archivo. En el detalle contiene el `nombre` y `descripcion` del archivo que se desea agregar.
+   */
+  confirmDocumentCreation(event: CustomEvent) {
+    const { nombre } = event.detail;
+
+    // Antes que nada, se chequea que empiece con mayúscula
+    if (!STARTS_WITH_CAPITAL_LETTER_REGEX.test(nombre)) {
+      this.showNotification("warning", "i18n.warning.file.capitalLetter");
+      return;
+    }
+
+    const document = new MDocument();
+    document.text_doc = "";
+    document.title = nombre;
+    document.parent_id = this.directorioActual.id;
+
+    const that = this;
+    const idDirectorioActual = this.directorioActual.id;
+
+    this.documentService
+      .createDocument(document, this.grupoSeleccionado.id)
+      .subscribe(
+        () => {
+          that.loadFilesAndFolders(
+            this.grupoSeleccionado.id,
+            idDirectorioActual
+          );
+
+          that.modalCreateFileOpened = false;
+        },
+        (error) => {
+          that.notifService.error(error.text());
+
+          that.modalCreateFileOpened = false;
+        }
+      );
   }
 }
diff --git a/Frontend Angular 4/src/app/layout/layout-routing.module.ts b/Frontend Angular 4/src/app/layout/layout-routing.module.ts
index 0e510bbbf313e7941ae83f5ab80d39bb75aec17a..9a4cbb8b60560d497c24f760a49b9c0211be4e5b 100755
--- a/Frontend Angular 4/src/app/layout/layout-routing.module.ts	
+++ b/Frontend Angular 4/src/app/layout/layout-routing.module.ts	
@@ -17,6 +17,11 @@ const routes: Routes = [
         loadChildren: () =>
           import("./matefun/matefun.module").then((m) => m.MateFunModule),
       },
+      {
+        path: "grupos/:groupId/users/:groupUserId/matefun/:id",
+        loadChildren: () =>
+          import("./matefun/matefun.module").then((m) => m.MateFunModule),
+      },
       {
         path: "archivos",
         loadChildren: () =>
diff --git a/Frontend Angular 4/src/app/layout/layout.module.ts b/Frontend Angular 4/src/app/layout/layout.module.ts
index 5159725bfc441c4d72eebd9e0fbc29d682ffa378..ca4ed8ee8e05b73190189f9a7e3167c4368d5c22 100755
--- a/Frontend Angular 4/src/app/layout/layout.module.ts	
+++ b/Frontend Angular 4/src/app/layout/layout.module.ts	
@@ -10,6 +10,9 @@ import { AuthenticationService } from "../shared/services/authentication.service
 import { HaskellService } from "../shared/services/haskell.service";
 import { DocumentService } from "../shared/services/document.service";
 import { FileService } from "../shared/services/file.service";
+import { GroupDocumentService } from "../shared/services/group-document.service";
+import { GroupFileService } from "../shared/services/group-file.service";
+import { GroupService } from "../shared/services/group.service";
 import { LtCodemirrorModule } from "lt-codemirror";
 import { CodemirrorModule } from "@ctrl/ngx-codemirror";
 import { NotificacionModule } from "../notificacion/notificacion.module";
@@ -34,6 +37,9 @@ import { TitleCaseModule } from "../shared/modules/titlecase.module";
     HaskellService,
     DocumentService,
     FileService,
+    GroupDocumentService,
+    GroupFileService,
+    GroupService,
   ],
 })
 export class LayoutModule {}
diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html
index 15d5a3eae914138397edff6f99518365dce6bd2c..7dbe99cc4aab0c17d980977ac55f9c886dc7a311 100755
--- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.html	
+++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.html	
@@ -169,6 +169,32 @@
                   >
                     <i class="fa fa-plus"></i>
                   </button>
+                  <button
+                    *ngIf="canRequestFeedback()"
+                    style="float: right"
+                    (click)="requestFeedback()"
+                    class="btn btn-sm btn-secondary"
+                    ngbPopover="{{
+                      'i18n.action.requestFeedback' | translate | titleCase
+                    }} {{ 'i18n.object.file' | translate | titleCase }}"
+                    triggers="mouseenter:mouseleave"
+                    placement="bottom"
+                  >
+                    <i class="fa fa-exchange"></i>
+                  </button>
+                  <button
+                    *ngIf="canReturnFeedback()"
+                    style="float: right"
+                    (click)="returnFeedback()"
+                    class="btn btn-sm btn-secondary"
+                    ngbPopover="{{
+                      'i18n.action.returnFeedback' | translate | titleCase
+                    }} {{ 'i18n.object.file' | translate | titleCase }}"
+                    triggers="mouseenter:mouseleave"
+                    placement="bottom"
+                  >
+                    <i class="fa fa-exchange"></i>
+                  </button>
                   <ng-template #popoverContent style="width: 15em">
                     <div style="width: 12em">
                       <div class="form-group">
diff --git a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts
index 5f65fc1d10c4175b71b93455462a47062f386b04..1906dd16ffef31d0ce8d097e163629d5fe74ba3e 100755
--- a/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts	
+++ b/Frontend Angular 4/src/app/layout/matefun/matefun.component.ts	
@@ -14,6 +14,7 @@ import { HaskellService } from "../../shared/services/haskell.service";
 import { DocumentService } from "../../shared/services/document.service";
 import { UserService } from "../../shared/services/user.service";
 import { FileService } from "../../shared/services/file.service";
+import { GroupFileService } from "../../shared/services/group-file.service";
 import { WebsocketService } from "../../shared/services/websocket.service";
 import { ActionCableService } from "app/shared/services/actioncable.service";
 import { UsuarioService } from "../../shared/services/usuario.service";
@@ -41,7 +42,12 @@ import { CodeMirrorBinding } from "y-codemirror";
 import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
 import { CreateFileModal } from "../../shared/components/create-file-modal/create-file-modal.component";
 import { ImportFileModal } from "../../shared/components/import-file-modal/import-file-modal.component";
-import { ShareFileModal } from "app/shared";
+import {
+  ShareFileModal,
+  RequestFeedbackModal,
+  ReturnFeedbackModal,
+} from "app/shared";
+import { GroupDocumentService } from "../../shared/services/group-document.service";
 
 import * as Y from "yjs";
 
@@ -67,7 +73,8 @@ import "./codemirror/addons/functions_definition_EN.js";
 import "./codemirror/addons/functions_definition_ES.js";
 import { Action } from "rxjs/internal/scheduler/Action";
 import { findInTree, roleCanShareFile } from "app/utils";
-import { filter } from "rxjs";
+import { filter, Observable } from "rxjs";
+import { GroupService } from "app/shared/services/group.service";
 
 var codeMirrorRef: any;
 var componentRef: any;
@@ -80,6 +87,8 @@ var focus: any;
   providers: [WebsocketService, NgbPopoverConfig, UsuarioService],
 })
 export class MateFunComponent implements OnInit, OnChanges {
+  currentUserGroupRole: string;
+  documentBelongsToCurrentUser: boolean;
   titlecasePipe: any;
   translateService: any;
   consoleDisable: boolean = false;
@@ -180,6 +189,8 @@ export class MateFunComponent implements OnInit, OnChanges {
   activeTabId = 1;
   ydoc: null | Y.Doc = null;
   documentId: number | null = null;
+  groupId: number | null = null;
+  groupUserId: number | null = null;
   editorContainer: Element;
   editor: CodeMirror.Editor;
   yUndoManager: Y.UndoManager;
@@ -224,6 +235,7 @@ export class MateFunComponent implements OnInit, OnChanges {
     private documentService: DocumentService,
     private userService: UserService,
     private fileService: FileService,
+    private groupFileService: GroupFileService,
     private authService: AuthenticationService,
     private ghciService: GHCIService,
     private notifService: NotificacionService,
@@ -231,6 +243,8 @@ export class MateFunComponent implements OnInit, OnChanges {
     private usuarioService: UsuarioService,
     public translate: TranslateService,
     private actionCableService: ActionCableService,
+    public groupDocumentService: GroupDocumentService,
+    public groupService: GroupService,
     private router: Router,
     private route: ActivatedRoute,
     private modalService: NgbModal,
@@ -399,10 +413,51 @@ export class MateFunComponent implements OnInit, OnChanges {
 
   getCurrentDocument(nextFunction: () => void = null) {
     this.documentId = parseInt(this.route.snapshot.paramMap.get("id"));
-    this.documentService.getDocument(this.documentId).subscribe({
+    this.groupId = parseInt(this.route.snapshot.paramMap.get("groupId"));
+    this.groupUserId = parseInt(
+      this.route.snapshot.paramMap.get("groupUserId")
+    );
+    let documentSubscription: Observable<{
+      document: MDocument;
+    }> = null;
+    let fileSubscriptionService: {
+      getFile: (id: number) => Observable<{
+        file: MFile;
+      }>;
+    } = null;
+    // TODO: Do something similar to this but for files,
+    // also the redirect to here when choosing a file in the groups page
+    // is setting the wrong user id
+    if (!!this.groupId && !!this.groupUserId) {
+      documentSubscription = this.groupDocumentService.getGroupDocument(
+        this.groupId,
+        this.documentId,
+        this.groupUserId
+      );
+
+      fileSubscriptionService =
+        this.groupFileService.getSpecificUserFileWithSetGroup(
+          this.groupId,
+          this.groupUserId
+        );
+    } else {
+      documentSubscription = this.documentService.getDocument(this.documentId);
+      fileSubscriptionService = this.fileService;
+    }
+    documentSubscription.subscribe({
       next: (data) => {
         this.archivo = this.documentService.documentToArchivo(data.document);
-        if (!!nextFunction) {
+        if (this.router.url.includes("grupos")) {
+          fileSubscriptionService
+            .getFile(this.archivo.fileId)
+            .subscribe((file) => {
+              this.archivo.feedbackRequested = file["file"].feedback_requested;
+
+              if (!!nextFunction) {
+                nextFunction();
+              }
+            });
+        } else if (!!nextFunction) {
           nextFunction();
         }
       },
@@ -412,6 +467,82 @@ export class MateFunComponent implements OnInit, OnChanges {
     });
   }
 
+  canRequestFeedback() {
+    return (
+      !!this.groupId &&
+      !!this.archivo &&
+      this.archivo.feedbackRequested !== undefined &&
+      !this.archivo.feedbackRequested &&
+      this.documentBelongsToCurrentUser
+    );
+  }
+
+  canReturnFeedback() {
+    return (
+      !!this.groupId &&
+      !!this.archivo &&
+      this.archivo.feedbackRequested !== undefined &&
+      this.archivo.feedbackRequested &&
+      this.groupService.userCanReturnFeedback(this.currentUserGroupRole)
+    );
+    // TODO: Do this and the other function
+  }
+
+  requestFeedback() {
+    this.openRequestFeedbackModal();
+  }
+
+  returnFeedback() {
+    this.openReturnFeedbackModal();
+  }
+
+  openRequestFeedbackModal() {
+    if (!this.groupId) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    if (!this.archivo.fileId) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(RequestFeedbackModal);
+
+    this.createModalRef.componentInstance.groupName = null;
+    this.createModalRef.componentInstance.groupId = this.groupId;
+    this.createModalRef.componentInstance.fileName = this.archivo.nombre;
+    this.createModalRef.componentInstance.fileId = this.archivo.fileId;
+    this.createModalRef.componentInstance.confirmFeedbackRequested =
+      this.confirmFeedbackRequsted;
+  }
+
+  confirmFeedbackRequsted() {}
+
+  openReturnFeedbackModal() {
+    if (!this.groupId) {
+      this.showNotification("warning", "i18n.warning.group.noSelected");
+      return;
+    }
+
+    if (!this.archivo.fileId) {
+      this.showNotification("warning", "i18n.warning.file.noSelected");
+      return;
+    }
+
+    this.createModalRef = this.modalService.open(ReturnFeedbackModal);
+
+    this.createModalRef.componentInstance.groupName = null;
+    this.createModalRef.componentInstance.groupId = this.groupId;
+    this.createModalRef.componentInstance.fileName = this.archivo.nombre;
+    this.createModalRef.componentInstance.fileId = this.archivo.fileId;
+    this.createModalRef.componentInstance.userId = this.groupUserId;
+    this.createModalRef.componentInstance.confirmFeedbackReturned =
+      this.confirmFeedbackReturned;
+  }
+
+  confirmFeedbackReturned() {}
+
   ngOnChanges() {
     // const docId = this.route.snapshot.paramMap.get("id");
     // this.confirmFileCreation = this.confirmFileCreation.bind(this);
@@ -458,10 +589,34 @@ export class MateFunComponent implements OnInit, OnChanges {
     this.configCodeMirrorDefinicion["readOnly"] = true;
 
     // This was always on ngOnInit
+
+    this.groupId = !!this.route.snapshot.paramMap.get("groupId")
+      ? parseInt(this.route.snapshot.paramMap.get("groupId"))
+      : null;
+    this.groupUserId = !!this.route.snapshot.paramMap.get("groupUserId")
+      ? parseInt(this.route.snapshot.paramMap.get("groupUserId"))
+      : null;
+
     if (!!this.route.snapshot.paramMap.get("id")) {
       this.getCurrentDocument(() => {
         this.copiaContenidoArchivo = this.archivo.contenido;
         this.copiaNombreArchivo = this.archivo.nombre;
+
+        if (
+          this.router.url.includes("grupos") &&
+          !!this.groupId &&
+          !!this.groupUserId
+        ) {
+          this.groupFileService
+            .getSpecificUserGroupFiles(this.groupId, this.groupUserId)
+            .subscribe((data) => {
+              this.importFilesData(data);
+            });
+        } else {
+          this.fileService.getFiles().subscribe((data) => {
+            this.importFilesData(data);
+          });
+        }
       });
     } else {
       this.newFile();
@@ -587,39 +742,30 @@ export class MateFunComponent implements OnInit, OnChanges {
     } else {
       this.configCodeMirror.mode.name = "matefun-ES";
     }
+  }
 
-    this.fileService.getFiles().subscribe((files) => {
-      let matefun_files = files["files"];
-      matefun_files = this.fileService.completeFiles(matefun_files);
-      this.sessionService.setUserFiles(matefun_files);
-      let fileArchivos = this.fileService.fileToArchivo(matefun_files);
-
-      this.archivosTree = fileArchivos;
-      if (!!this.editor) {
-        (this.editor as any).options.files = this.archivosTree;
-      }
-      this.sessionService.setArchivosTree(this.archivosTree);
-    });
-
-    this.fileService.getFiles().subscribe((data) => {
-      let matefun_files = data["files"];
-      matefun_files = this.fileService.completeFiles(matefun_files);
-      const tree = this.fileService.fileToArchivo(matefun_files);
-      this.archivosTree = tree;
-      this.sessionService.setArchivosTree(tree);
-      const file = findInTree([tree], this.archivo.fileId);
-      const directorioActual = findInTree([tree], file.padreId);
-      this.sessionService.setDirectorioActual(directorioActual);
-      this.documentService
-        .getDocuments(
-          directorioActual.archivos.map((archivo) => {
-            return archivo.documentId;
-          })
-        )
-        .subscribe((data) => {
-          this.sessionService.setCurrentDirectoryDocuments(data["documents"]);
-        });
-    });
+  importFilesData(data) {
+    let matefun_files = data["files"];
+    matefun_files = this.fileService.completeFiles(matefun_files);
+    this.sessionService.setUserFiles(matefun_files);
+    const tree = this.fileService.fileToArchivo(matefun_files);
+    this.archivosTree = tree;
+    if (!!this.editor) {
+      (this.editor as any).options.files = this.archivosTree;
+    }
+    this.sessionService.setArchivosTree(tree);
+    const file = findInTree([tree], this.archivo.fileId);
+    const directorioActual = findInTree([tree], file.padreId);
+    this.sessionService.setDirectorioActual(directorioActual);
+    this.documentService
+      .getDocuments(
+        directorioActual.archivos.map((archivo) => {
+          return archivo.documentId;
+        })
+      )
+      .subscribe((data) => {
+        this.sessionService.setCurrentDirectoryDocuments(data["documents"]);
+      });
   }
 
   ngAfterViewInit() {
@@ -764,18 +910,40 @@ export class MateFunComponent implements OnInit, OnChanges {
 
   initializeEditor() {
     let readOnly = false;
+
     if (!!this.archivo.users) {
       if (this.archivo.users.length > 0) {
         const id = JSON.parse(localStorage.getItem("currentUser"))["id"];
-        readOnly =
-          this.archivo.users.find((user) => {
-            return user.id === id;
-          }).role === "viewer";
+        const user = this.archivo.users.find((user) => {
+          return user.id === id;
+        });
+        this.documentBelongsToCurrentUser = !!user;
+
+        if (!!user) {
+          readOnly = user.role === "viewer";
+        }
+
+        if ((!user || readOnly == true) && !!this.groupId) {
+          const id = JSON.parse(localStorage.getItem("currentUser"))["id"];
+          this.groupService.getUserRole(this.groupId, id).subscribe((data) => {
+            this.currentUserGroupRole = data.role.role;
 
-        this.editor.setOption("readOnly", readOnly);
+            this.editor.setOption(
+              "readOnly",
+              !this.groupService.userCanEditAnyGroupFile(
+                this.currentUserGroupRole
+              )
+            );
+          });
+        } else {
+          this.editor.setOption("readOnly", readOnly);
+        }
       } else {
+        this.documentBelongsToCurrentUser = true;
         this.editor.setOption("readOnly", false);
       }
+    } else {
+      this.documentBelongsToCurrentUser = true;
     }
 
     if (!!this.binding) {
@@ -802,11 +970,22 @@ export class MateFunComponent implements OnInit, OnChanges {
 
     this.ydoc = yDocument;
 
+    let params: Record<string, string> = {
+      doc_id: this.documentId?.toString(),
+    };
+    if (!!this.groupId && !!this.groupUserId) {
+      params = {
+        ...params,
+        user_id: this.groupUserId.toString(),
+        group_id: this.groupId.toString(),
+      };
+    }
+
     this.provider = new WebsocketProvider(
       this.ydoc,
       this.actionCableService.consumer,
       "ApplicationCable::DocumentChannel",
-      { doc_id: this.documentId?.toString() }
+      params
     );
 
     let awareness = undefined;
diff --git a/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.html b/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..f80e61cb641a4c8ddacc5dc720cb83c0efbf5a47
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.html	
@@ -0,0 +1,27 @@
+<div class="modal-header">
+  <span class="modal-title font-bold" id="modal-title">{{ title }}</span>
+  <button
+    aria-label="Cerrar diálogo"
+    (click)="cancelAction()"
+    part="close-button"
+    class="close-button fa fa-close"
+    type="button"
+  ></button>
+</div>
+<div class="modal-body">
+  <div class="mb-3">
+    {{ message }}
+  </div>
+  <div class="flex justify-end">
+    <button
+      (click)="cancelAction()"
+      class="btn btn-secondary mr-3"
+      slot="secondary"
+    >
+      Cancelar
+    </button>
+    <button (click)="confirmAction()" class="btn btn-primary" slot="primary">
+      Confirmar
+    </button>
+  </div>
+</div>
diff --git a/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.ts b/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..47b26b3520a71277d158e4031f28e0f558d4ae69
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/action-confirmation-modal/action-confirmation-modal.component.ts	
@@ -0,0 +1,15 @@
+import { Component, ChangeDetectionStrategy, Input } from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+@Component({
+  selector: "app-action-confirmation-modal",
+  templateUrl: "./action-confirmation-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ActionConfirmationModal {
+  @Input() title: string;
+  @Input() message: string;
+  @Input() confirmAction: () => void;
+  @Input() cancelAction: () => void;
+}
diff --git a/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.html b/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..a8a4e237cc407b6b56ae8bb1fcf2448a6e2dbc83
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.html	
@@ -0,0 +1,33 @@
+<div class="modal-header">
+  <span class="modal-title font-bold" id="modal-title">{{ title }}</span>
+  <button
+    aria-label="Cerrar diálogo"
+    (click)="modal.dismiss('Close assign file modal')"
+    part="close-button"
+    class="close-button fa fa-close"
+    type="button"
+  ></button>
+</div>
+<div class="modal-body">
+  <div class="flex flex-col justify-between w-full">
+    <label for="new-users">Users</label>
+    <div class="flex justify-between w-full items-center">
+      <app-checkbox-select
+        [(entities)]="users"
+        entitiesName="user"
+        filterName="role"
+        class="w-full"
+      ></app-checkbox-select>
+    </div>
+  </div>
+  <div class="flex justify-end mt-2">
+    <button
+      (click)="assignFile()"
+      [disabled]="selectedUsers().length === 0"
+      class="btn btn-primary"
+      slot="primary"
+    >
+      Asignar
+    </button>
+  </div>
+</div>
diff --git a/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.ts b/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d7136f21da6e7ebe19bf8c7031e48e15273d6150
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/assign-file-modal/assign-file-modal.component.ts	
@@ -0,0 +1,79 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+  ChangeDetectorRef,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { GroupFileService } from "../../services/group-file.service";
+
+import { selectableUser } from "../../objects/archivo-types";
+
+@Component({
+  selector: "app-assign-file-modal",
+  templateUrl: "./assign-file-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AssignFileModal implements OnInit {
+  @Input() fileName: string;
+  @Input() groupName: string | null;
+  @Input() groupId: number;
+  @Input() fileId: number;
+
+  @Input() users: selectableUser[] = [];
+  @Input() userFilter: string = null;
+
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  @Input() confirmFileAssigned: () => void;
+  title = "Asignar archivo";
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupFileService: GroupFileService,
+    private changeDetectorRef: ChangeDetectorRef
+  ) {}
+
+  ngOnInit(): void {
+    this.fileName = `${this.fileName}`;
+
+    if (!!this.groupName) {
+      this.groupName = `${this.groupName}`;
+      this.title = `¿Asignar archivo ${this.fileName} en el grupo ${this.groupName}?`;
+    } else {
+      this.title = `¿Asignar archivo ${this.fileName}?`;
+    }
+
+    this.assignFile = this.assignFile.bind(this);
+    this.cancel = this.cancel.bind(this);
+  }
+
+  selectedUsers() {
+    return this.users.filter((user) => user.selected);
+  }
+
+  assignFile(): void {
+    this.groupFileService
+      .assignFile(
+        this.groupId,
+        this.fileId,
+        this.users.filter((user) => user.selected).map((user) => user.id),
+        [] // subgroups.map((subgroup) => subgroup.id)
+      )
+      .subscribe({
+        next: (_) => {
+          this.confirmFileAssigned();
+          this.modal.close();
+        },
+        error: (error) => console.log(error),
+      });
+  }
+
+  cancel(): void {
+    this.modal.dismiss();
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.html b/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..80297d1ac59e6b9bf30d961d922c789b3c4c74d0
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.html	
@@ -0,0 +1,38 @@
+<div class="flex flex-col justify-between w-full">
+  <label for="new-users">Something</label>
+</div>
+<table class="table-fixed w-96 mx-auto">
+  <thead>
+    <tr>
+      <th>
+        <mat-checkbox
+          [checked]="allEntitiesSelected()"
+          (change)="onCheckboxChange($event.checked)"
+        >
+        </mat-checkbox>
+      </th>
+      <th>{{ entitiesName }}</th>
+      <th *ngIf="{filterName}">{{ filterName }}</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr
+      *ngFor="let entity of entities"
+      (mouseup)="selectDeselectEntity(entity)"
+      class="hover:bg-gray-200"
+    >
+      <th>
+        <mat-checkbox
+          #inputCheckbox
+          [checked]="entity.selected"
+          (change)="selectDeselectEntity(entity)"
+        >
+        </mat-checkbox>
+      </th>
+      <td>{{ entity.username }}</td>
+      <ng-container *ngIf="{filterName}">
+        <td>{{ entity[filterName] }}</td>
+      </ng-container>
+    </tr>
+  </tbody>
+</table>
diff --git a/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.ts b/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4aff60643190e88dfa010d8229e1d5cdf28ed26f
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/checkbox-select/checkbox-select.component.ts	
@@ -0,0 +1,64 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  Output,
+  EventEmitter,
+  OnInit,
+  ChangeDetectorRef,
+  OnChanges,
+  SimpleChanges,
+} from "@angular/core";
+
+import { selectableUser } from "../../objects/archivo-types";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+@Component({
+  selector: "app-checkbox-select",
+  templateUrl: "./checkbox-select.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CheckboxSelect implements OnInit, OnChanges {
+  @Input() entitiesName: string;
+  @Input() entities: selectableUser[] = [];
+  @Input() filterName: string;
+  @Output() entitiesChanged = new EventEmitter<selectableUser[]>();
+
+  constructor(
+    public modal: NgbActiveModal,
+    private changeDetectorRef: ChangeDetectorRef
+  ) {}
+
+  ngOnInit(): void {}
+
+  ngOnChanges(changes: SimpleChanges): void {
+    // if (!!changes.users) {
+    //   this.users.forEach((user) => {
+    //     this.usersObject[user.id] = user.role;
+    //   });
+    // }
+  }
+
+  selectDeselectEntity(entity: selectableUser): void {
+    entity.selected = !entity.selected;
+    this.entitiesChange(this.entities);
+  }
+
+  entitiesChange(entities: selectableUser[]): void {
+    this.entities = entities;
+    this.entitiesChanged.emit(this.entities);
+    this.changeDetectorRef.detectChanges();
+  }
+
+  allEntitiesSelected() {
+    return this.entities.every((entity) => entity.selected);
+  }
+
+  onCheckboxChange(checked: boolean): void {
+    this.entities.forEach((entity) => {
+      entity.selected = checked;
+    });
+    this.entitiesChange(this.entities);
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.html b/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..b49e958e9ef667c882d1f416b85b18f2c596c38a
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.html	
@@ -0,0 +1,33 @@
+<div class="modal-header">
+  <span class="modal-title font-bold" id="modal-title">{{ modalTitle }}</span>
+  <button
+    aria-label="Cerrar diálogo"
+    (click)="modal.dismiss('Close create group modal')"
+    part="close-button"
+    class="close-button fa fa-close"
+    type="button"
+  ></button>
+</div>
+<div class="modal-body">
+  <div class="flex flex-col space-between">
+    <label for="document-title">Group Name</label>
+    <input
+      type="text"
+      [(ngModel)]="groupName"
+      placeholder="Enter group name"
+      ngbAutofocus
+      id="group-name"
+      class="name-input border-opacity-25 border-black border-2 rounded w-full px-2 py-3 text-base focus-visible:border-focused-blue focus:outline-transparent"
+    />
+  </div>
+  <div class="flex justify-end mt-4">
+    <button
+      (click)="confirmGroupCreation(groupName)"
+      [disabled]="!groupName"
+      class="btn btn-primary"
+      slot="primary"
+    >
+      Crear Grupo
+    </button>
+  </div>
+</div>
diff --git a/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.ts b/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..05cba8db5067dd2c7a07ef601ba0895bb91bfdcd
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/create-group-modal/create-group-modal.component.ts	
@@ -0,0 +1,38 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { MFile } from "../../objects/archivo-types";
+import { Group } from "../../objects/grupo";
+import { FileService } from "../../services/file.service";
+import { GroupService } from "../../services/group.service";
+
+@Component({
+  selector: "app-create-group-modal",
+  templateUrl: "./create-group-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CreateGroupModal implements OnInit {
+  @Input() modalTitle: string;
+  @Input() groupName: string;
+
+  /**
+   * Se dispara cuando se confirma la creación del archivo en el directorio actual.
+   */
+  @Input() confirmGroupCreation: (title: string) => void;
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupService: GroupService
+  ) {}
+
+  ngOnInit(): void {
+    this.groupName = `${this.groupName || ""}`;
+    this.modalTitle = `${this.modalTitle}`;
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.html b/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..0451b0ce81c5184153c2fcf24d5de5b2b621d11e
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.html	
@@ -0,0 +1,6 @@
+<app-action-confirmation-modal
+  [title]="title"
+  [message]="message"
+  [confirmAction]="destroyGroup"
+  [cancelAction]="cancel"
+></app-action-confirmation-modal>
diff --git a/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.ts b/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4b4582fbb8c65df9b93ed204a3030dd4f8ed79a
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/destroy-group-modal/destroy-group-modal.component.ts	
@@ -0,0 +1,60 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { GroupService } from "../../services/group.service";
+
+@Component({
+  selector: "app-destroy-group-modal",
+  templateUrl: "./destroy-group-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DestroyGroupModal implements OnInit {
+  @Input() groupName: string;
+  @Input() groupId: number;
+  @Input() userRole: string;
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  @Input() confirmGroupDestroyed: () => void;
+  title: string;
+  message: string;
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupService: GroupService
+  ) {}
+
+  ngOnInit(): void {
+    this.groupName = `${this.groupName}`;
+
+    if (this.userRole === "owner") {
+      this.title = "Destruir Grupo";
+      this.message = `¿Estás seguro de que deseas destruir el grupo ${this.groupName}?`;
+    } else {
+      this.title = "Abandonar Grupo";
+      this.message = `¿Estás seguro de que desea abandonar el grupo ${this.groupName}?`;
+    }
+    this.destroyGroup = this.destroyGroup.bind(this);
+    this.cancel = this.cancel.bind(this);
+  }
+
+  destroyGroup(): void {
+    this.groupService.destroyGroup(this.groupId).subscribe({
+      next: (_) => {
+        this.confirmGroupDestroyed();
+        this.modal.close();
+      },
+      error: (error) => console.log(error),
+    });
+  }
+
+  cancel(): void {
+    this.modal.dismiss();
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/index.ts b/Frontend Angular 4/src/app/shared/components/index.ts
index 381d0ed39e0186d8d7561acd39e24b27d9b25d42..88229485e2bf876c7d75857d5905cd79a375f820 100755
--- a/Frontend Angular 4/src/app/shared/components/index.ts	
+++ b/Frontend Angular 4/src/app/shared/components/index.ts	
@@ -8,3 +8,11 @@ export * from "./share-file-modal/share-file-modal.component";
 export * from "./chip-input/chip-input.component";
 export * from "./select/select.component";
 export * from "./add-users-modal/add-users-modal.component";
+export * from "./create-group-modal/create-group-modal.component";
+export * from "./manage-group-users-modal/manage-group-users-modal.component";
+export * from "./action-confirmation-modal/action-confirmation-modal.component";
+export * from "./destroy-group-modal/destroy-group-modal.component";
+export * from "./request-feedback-modal/request-feedback-modal.component";
+export * from "./return-feedback-modal/return-feedback-modal.component";
+export * from "./assign-file-modal/assign-file-modal.component";
+export * from "./checkbox-select/checkbox-select.component";
diff --git a/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.html b/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..891497b1ca02d6d123f122d2a4b03c09befa507f
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.html	
@@ -0,0 +1,11 @@
+<app-add-users-modal
+  [modalTitle]="modalTitle"
+  [(chips)]="chips"
+  [newUserRolesEnum]="newUsersPermissionsEnum"
+  [newUserRole]="newUsersPermission"
+  (close)="modal.dismiss('Close manage user\'s group modal')"
+  [users]="usersCopy"
+  [rolesField]="groupRole"
+  [requiredRole]="'Owner'"
+  [save]="save"
+></app-add-users-modal>
diff --git a/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.ts b/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a8dfef43c4791a79fe2ad3db4116a1518fe77e44
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/manage-group-users-modal/manage-group-users-modal.component.ts	
@@ -0,0 +1,69 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+  ChangeDetectorRef,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { User } from "../../objects/archivo-types";
+import { Group } from "../../objects/grupo";
+import { GroupService } from "../../services/group.service";
+
+@Component({
+  selector: "app-manage-group-users-modal",
+  templateUrl: "./manage-group-users-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ManageGroupUsersModal implements OnInit {
+  @Input() modalTitle: string;
+  @Input() groupName: string;
+  @Input() groupId: number;
+  group: Group;
+  newUsersPermissionsEnum: string[] = [
+    "Owner",
+    "Manager",
+    "Moderator",
+    "Member",
+  ];
+  newUsersPermission = this.newUsersPermissionsEnum[3];
+  users: User[] = [];
+  usersCopy: User[] = [];
+  groupRole = "role";
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  @Input() confirmGroupUpdated: () => void;
+
+  chips: string[] = [];
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupService: GroupService,
+    private changeDetectorRef: ChangeDetectorRef
+  ) {}
+
+  ngOnInit(): void {
+    this.groupService.getGroup(this.groupId).subscribe((groupResponse) => {
+      this.group = groupResponse.group;
+      this.users = groupResponse.group.users;
+      this.usersCopy = [...this.users];
+      this.changeDetectorRef.detectChanges();
+    });
+    this.groupName = `${this.groupName}`;
+    this.modalTitle = `${this.modalTitle}`;
+    this.save = this.save.bind(this);
+  }
+
+  save(userData: { id?: number; username: string; role: string }[]): void {
+    this.groupService.updateGroup(this.group.id, userData).subscribe({
+      next: (_) => {
+        this.confirmGroupUpdated();
+        this.modal.close();
+      },
+      error: (error) => console.log(error),
+    });
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.html b/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..626e7c6ab99157c67b1b6d00cae37ac92ae214e1
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.html	
@@ -0,0 +1,6 @@
+<app-action-confirmation-modal
+  [title]="title"
+  [message]="message"
+  [confirmAction]="requestFeedback"
+  [cancelAction]="cancel"
+></app-action-confirmation-modal>
diff --git a/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.ts b/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..968d5e14c22db44915a25ca06f2967fea8cf029c
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/request-feedback-modal/request-feedback-modal.component.ts	
@@ -0,0 +1,63 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { GroupFileService } from "../../services/group-file.service";
+
+@Component({
+  selector: "app-request-feedback-modal",
+  templateUrl: "./request-feedback-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class RequestFeedbackModal implements OnInit {
+  @Input() fileName: string;
+  @Input() groupName: string | null;
+  @Input() groupId: number;
+  @Input() fileId: number;
+
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  @Input() confirmFeedbackRequested: () => void;
+  title = "Pedir retroalimentación";
+  message: string;
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupFileService: GroupFileService
+  ) {}
+
+  ngOnInit(): void {
+    this.fileName = `${this.fileName}`;
+
+    if (!!this.groupName) {
+      this.groupName = `${this.groupName}`;
+      this.message = `¿Desea pedir retroalimentación del archivo ${this.fileName} en el grupo ${this.groupName}?`;
+    } else {
+      this.message = `¿Desea pedir retroalimentación del archivo ${this.fileName}?`;
+    }
+
+    this.requestFeedback = this.requestFeedback.bind(this);
+    this.cancel = this.cancel.bind(this);
+  }
+
+  requestFeedback(): void {
+    this.groupFileService.requestFeedback(this.groupId, this.fileId).subscribe({
+      next: (_) => {
+        this.confirmFeedbackRequested();
+
+        this.modal.close();
+      },
+      error: (error) => console.log(error),
+    });
+  }
+
+  cancel(): void {
+    this.modal.dismiss();
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.html b/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..0451b0ce81c5184153c2fcf24d5de5b2b621d11e
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.html	
@@ -0,0 +1,6 @@
+<app-action-confirmation-modal
+  [title]="title"
+  [message]="message"
+  [confirmAction]="destroyGroup"
+  [cancelAction]="cancel"
+></app-action-confirmation-modal>
diff --git a/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.ts b/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f81dd51a21b8122c9ac87550ed15ba5a994741c
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/request-group-file-feedback-modal/request-group-file-feedback-modal.component.ts	
@@ -0,0 +1,54 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { GroupService } from "../../services/group.service";
+
+@Component({
+  selector: "app-destroy-group-modal",
+  templateUrl: "./destroy-group-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class RequestGroupFileModal implements OnInit {
+  @Input() groupName: string;
+  @Input() fileName: string;
+  @Input() groupId: number;
+  @Input() fileId: number;
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  title: string;
+  message: string;
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupService: GroupService
+  ) {}
+
+  ngOnInit(): void {
+    this.groupName = `${this.groupName}`;
+
+    this.title = "Pedir Retroalimentación";
+    this.message = `¿Estás seguro de que desea pedir retroalimentación para el archivo ${this.fileName}? \n Esta decisión no se puede deshacer.`;
+    this.requestFeedback = this.requestFeedback.bind(this);
+    this.cancel = this.cancel.bind(this);
+  }
+
+  requestFeedback(): void {
+    this.groupService.requestFeedback(this.groupId, this.fileId).subscribe({
+      next: (_) => {
+        this.modal.close();
+      },
+      error: (error) => console.log(error),
+    });
+  }
+
+  cancel(): void {
+    this.modal.dismiss();
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.html b/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..8f8bd9d54121b24dccc760a9b5bb966afc823b0e
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.html	
@@ -0,0 +1,6 @@
+<app-action-confirmation-modal
+  [title]="title"
+  [message]="message"
+  [confirmAction]="returnFeedback"
+  [cancelAction]="cancel"
+></app-action-confirmation-modal>
diff --git a/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.ts b/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..422ebadf23a709d598f4afd5660c650a042af730
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/components/return-feedback-modal/return-feedback-modal.component.ts	
@@ -0,0 +1,66 @@
+import {
+  Component,
+  ChangeDetectionStrategy,
+  Input,
+  OnInit,
+} from "@angular/core";
+
+import { NgbActiveModal } from "@ng-bootstrap/ng-bootstrap";
+
+import { GroupFileService } from "../../services/group-file.service";
+
+@Component({
+  selector: "app-return-feedback-modal",
+  templateUrl: "./return-feedback-modal.component.html",
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ReturnFeedbackModal implements OnInit {
+  @Input() fileName: string;
+  @Input() groupName: string | null;
+  @Input() groupId: number;
+  @Input() fileId: number;
+  @Input() userId: number;
+
+  /**
+   * Se dispara cuando se quiere administrar los usuarios del grupo
+   */
+  @Input() confirmFeedbackReturned: () => void;
+  title = "Dar retroalimentación";
+  message: string;
+
+  constructor(
+    public modal: NgbActiveModal,
+    private groupFileService: GroupFileService
+  ) {}
+
+  ngOnInit(): void {
+    this.fileName = `${this.fileName}`;
+
+    if (!!this.groupName) {
+      this.groupName = `${this.groupName}`;
+      this.message = `¿Desea dar retroalimentación del archivo ${this.fileName} en el grupo ${this.groupName}?`;
+    } else {
+      this.message = `¿Desea dar retroalimentación del archivo ${this.fileName}?`;
+    }
+
+    this.returnFeedback = this.returnFeedback.bind(this);
+    this.cancel = this.cancel.bind(this);
+  }
+
+  returnFeedback(): void {
+    this.groupFileService
+      .returnFeedback(this.groupId, this.fileId, this.userId)
+      .subscribe({
+        next: (_) => {
+          this.confirmFeedbackReturned();
+
+          this.modal.close();
+        },
+        error: (error) => console.log(error),
+      });
+  }
+
+  cancel(): void {
+    this.modal.dismiss();
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/config.ts b/Frontend Angular 4/src/app/shared/config.ts
index f93b27ef46901b3b099edebbddfdeab7ed7edb59..01e774f111ad6e97e22a9733e1f63b536c87376f 100755
--- a/Frontend Angular 4/src/app/shared/config.ts	
+++ b/Frontend Angular 4/src/app/shared/config.ts	
@@ -50,3 +50,27 @@ export const CREATE_DOCUMENT = SERVER + "/api/v2/documents";
 export const UPDATE_DOCUMENT = SERVER + "/api/v2/documents";
 
 export const DESTROY_AUX_DOCUMENT = SERVER + "/api/v2/aux_documents";
+
+export const GET_GROUP = SERVER + "/api/v2/groups/:id";
+export const GET_GROUPS = SERVER + "/api/v2/groups";
+export const CREATE_GROUP = SERVER + "/api/v2/groups";
+export const UPDATE_GROUP = SERVER + "/api/v2/groups";
+export const DELETE_GROUP = SERVER + "/api/v2/groups";
+
+export const GET_GROUP_DOCUMENT =
+  SERVER + "/api/v2/groups/:group_id/documents/:id";
+export const GET_GROUP_FILE = SERVER + "/api/v2/groups/:group_id/files/:id";
+export const GET_GROUP_FILES = SERVER + "/api/v2/groups/:group_id/files";
+export const GET_GROUP_FILES_LISTS =
+  SERVER + "/api/v2/groups/:group_id/files/lists";
+export const CREATE_GROUP_FILE = SERVER + "/api/v2/groups/:group_id/files";
+export const UPDATE_GROUP_FILE = SERVER + "/api/v2/groups/:group_id/files";
+export const DELETE_GROUP_FILE = SERVER + "/api/v2/groups/:group_id/files";
+export const GET_GROUP_FEEDBACK_REQUESTED_FILES =
+  SERVER + "/api/v2/groups/:group_id/feedback_requested_files";
+export const CREATE_GROUP_FILE_FEEDBACK_REQUEST =
+  SERVER + "/api/v2/groups/:group_id/feedback_requests";
+export const GET_GROUP_USER_ROLE =
+  SERVER + "/api/v2/groups/:group_id/users/:user_id/role";
+export const ASSIGN_FILE =
+  SERVER + "/api/v2/groups/:group_id/files/:file_id/assignment";
diff --git a/Frontend Angular 4/src/app/shared/objects/archivo-types.ts b/Frontend Angular 4/src/app/shared/objects/archivo-types.ts
index 15e62bc2f682a5f41e282ee7d6e732866bf6587e..e2dfc84351363d8e382656768649c58642ef085f 100755
--- a/Frontend Angular 4/src/app/shared/objects/archivo-types.ts	
+++ b/Frontend Angular 4/src/app/shared/objects/archivo-types.ts	
@@ -22,9 +22,11 @@ export class Archivo {
   eliminado: boolean;
   evaluacion: Evaluacion;
   documentId: number;
+  groupId?: number;
   fileId?: number;
   users?: User[];
   role?: string;
+  feedbackRequested?: boolean;
 
   constructor() {}
 }
@@ -39,8 +41,10 @@ export class MFile {
   parent_id?: number;
   directory: boolean;
   children?: MFile[];
+  group_id?: number;
   users?: User[];
   role?: string;
+  feedback_requested?: boolean;
 
   constructor() {}
 }
@@ -71,6 +75,10 @@ export class User {
   role?: string;
 }
 
+export class selectableUser extends User {
+  selected: boolean;
+}
+
 export class Grupo {
   anio: number;
   grado: number;
diff --git a/Frontend Angular 4/src/app/shared/objects/grupo.ts b/Frontend Angular 4/src/app/shared/objects/grupo.ts
index 9c9679ea7f3b6ad3e1a70627a3364a8ecd3b9ca6..832f2203eac529ce7b2b06e4515901bd51c506d9 100755
--- a/Frontend Angular 4/src/app/shared/objects/grupo.ts	
+++ b/Frontend Angular 4/src/app/shared/objects/grupo.ts	
@@ -1,27 +1,10 @@
-import { Archivo } from "./archivo-types";
-import { Usuario } from "./usuario";
+import { MFile } from "./archivo-types";
+import { User } from "./archivo-types";
 
-export class Grupo {
-  anio: number;
-  grado: number;
-  grupo: string;
-  liceoId: number;
-  archivos: Archivo[];
-  alumnos: Usuario[];
-
-  constructor(
-    anio: number,
-    grado: number,
-    grupo: string,
-    liceoId: number,
-    archivos: Archivo[],
-    alumnos: Usuario[]
-  ) {
-    this.anio = anio;
-    this.grado = grado;
-    this.grupo = grupo;
-    this.liceoId = liceoId;
-    this.archivos = archivos;
-    this.alumnos = alumnos;
-  }
+export class Group {
+  id: number;
+  name: string;
+  files?: MFile[];
+  users?: User[];
+  role?: string;
 }
diff --git a/Frontend Angular 4/src/app/shared/services/document.service.ts b/Frontend Angular 4/src/app/shared/services/document.service.ts
index e1df5247de7b5a732bd6aa89afa0e665758d5784..4978249cbead78eb5e44ea96f47142d61e193f52 100644
--- a/Frontend Angular 4/src/app/shared/services/document.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/document.service.ts	
@@ -13,7 +13,7 @@ import {
   MFile,
   MDocument,
 } from "../objects/archivo-types";
-import { Grupo } from "../objects/grupo";
+import { Group } from "../objects/grupo";
 
 import { SERVER } from "../config";
 import { TranslateService } from "@ngx-translate/core";
@@ -114,10 +114,17 @@ export class DocumentService {
     };
   }
 
-  createDocument(document: MDocument): Observable<HttpResponse<MDocument>> {
+  createDocument(
+    document: MDocument,
+    groupId?: number
+  ): Observable<HttpResponse<MDocument>> {
+    const params = { ...document };
+    if (groupId) {
+      params["group_id"] = groupId;
+    }
     return this.http.post<MDocument>(
       CREATE_DOCUMENT,
-      { document },
+      { document: params },
       {
         observe: "response",
         headers: this.postHeaders(),
@@ -262,14 +269,14 @@ export class DocumentService {
   }
 
   // Legacy method, need to check if it's still used
-  getGrupos(cedula: string): Observable<Grupo[]> {
+  getGrupos(cedula: string): Observable<Group[]> {
     let headers = this.getHeaders();
     let params: HttpParams = new HttpParams();
     params = params.set("cedula", cedula);
     let httpOptions = { headers: headers, params: params };
 
     return this.http
-      .get<Grupo[]>(SERVER + "/servicios/grupo", httpOptions)
+      .get<Group[]>(SERVER + "/servicios/grupo", httpOptions)
       .pipe(catchError(this.handleError));
   }
 
diff --git a/Frontend Angular 4/src/app/shared/services/file.service.ts b/Frontend Angular 4/src/app/shared/services/file.service.ts
index b900b573ddce9a147dfb7fcbae0657b107cfe20f..e67468b7ceaa65a788bb6adeb9c07a9ac6fdf2a4 100644
--- a/Frontend Angular 4/src/app/shared/services/file.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/file.service.ts	
@@ -8,7 +8,6 @@ import {
   HttpResponse,
 } from "@angular/common/http";
 import { Archivo, Evaluacion, MFile } from "../objects/archivo-types";
-import { Grupo } from "../objects/grupo";
 
 import { SERVER } from "../config";
 import { TranslateService } from "@ngx-translate/core";
@@ -108,6 +107,8 @@ export class FileService {
     archivo.evaluacion = null;
     archivo.users = file.users;
     archivo.role = file.role;
+    archivo.groupId = file.group_id;
+    archivo.feedbackRequested = file.feedback_requested;
 
     if (!!file.children) {
       archivo.archivos = file.children.map<Archivo>((child) => {
@@ -146,6 +147,8 @@ export class FileService {
       children: [],
       directory: archivo.directorio,
       role: archivo.role,
+      group_id: archivo.groupId,
+      feedback_requested: archivo.feedbackRequested,
     };
 
     file.children = archivo.archivos.map<MFile>((archivoHijo) => {
diff --git a/Frontend Angular 4/src/app/shared/services/group-document.service.ts b/Frontend Angular 4/src/app/shared/services/group-document.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a76638cad6223e59cc51b3499a22a3d02739df8e
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/services/group-document.service.ts	
@@ -0,0 +1,99 @@
+import { throwError as observableThrowError, Observable } from "rxjs";
+import { Injectable } from "@angular/core";
+import { Router } from "@angular/router";
+import {
+  HttpClient,
+  HttpHeaders,
+  HttpParams,
+  HttpResponse,
+} from "@angular/common/http";
+import {
+  Archivo,
+  Evaluacion,
+  MFile,
+  MDocument,
+} from "../objects/archivo-types";
+import { Group } from "../objects/grupo";
+
+import { SERVER } from "../config";
+import { TranslateService } from "@ngx-translate/core";
+import { AuthenticationService } from "./authentication.service";
+import { catchError } from "rxjs/operators";
+import { GET_GROUP_DOCUMENT } from "../config";
+
+@Injectable()
+export class GroupDocumentService {
+  translateService: any;
+
+  /**
+   * Creates a new DocumentService with the injected HttpClient.
+   * @param {HttpClient} http - The injected HttpClient.
+   * @constructor
+   */
+  constructor(
+    private http: HttpClient,
+    private router: Router,
+    private authService: AuthenticationService,
+    public translate: TranslateService
+  ) {
+    this.translateService = translate;
+  }
+
+  private getHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Authorization: "Bearer " + this.authService.getToken(),
+    });
+  }
+
+  private postHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Accept: "application/json",
+      "Access-Control-Allow-Headers": "Content-Type",
+    });
+  }
+
+  getGroupDocument(
+    groupId: number,
+    id: number,
+    userId: number
+  ): Observable<{ document: MDocument }> {
+    let params = {};
+    if (!!userId) {
+      params = new HttpParams().set("user_id", userId);
+    }
+    return this.http
+      .get<{ document: MDocument }>(
+        GET_GROUP_DOCUMENT.replace(/:group_id/g, String(groupId)).replace(
+          /:id/g,
+          String(id)
+        ),
+        {
+          headers: this.getHeaders(),
+          params: params,
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  /**
+   * Handle HTTP error
+   */
+  private handleError(error: any) {
+    if (error.status == 401) {
+      this.translateService
+        .get("i18n.code")
+        .subscribe((res) => this.router.navigate(["/" + res + "/login"]));
+    }
+    // In a real world app, we might use a remote logging infrastructure
+    // We'd also dig deeper into the error to get a better message
+    let errMsg = error.message
+      ? error.message
+      : error.status
+      ? `${error.status} - ${error.statusText}`
+      : "Server error";
+    console.error(errMsg); // log to console instead
+    return observableThrowError(errMsg);
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/services/group-file.service.ts b/Frontend Angular 4/src/app/shared/services/group-file.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e08db79a082739df50ad924a93a3d51bdd8f1961
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/services/group-file.service.ts	
@@ -0,0 +1,284 @@
+import { throwError as observableThrowError, Observable } from "rxjs";
+import { Injectable } from "@angular/core";
+import { Router } from "@angular/router";
+import {
+  HttpClient,
+  HttpHeaders,
+  HttpParams,
+  HttpResponse,
+} from "@angular/common/http";
+import { Archivo, Evaluacion, MFile } from "../objects/archivo-types";
+
+import { TranslateService } from "@ngx-translate/core";
+import { AuthenticationService } from "./authentication.service";
+import { catchError } from "rxjs/operators";
+import {
+  CREATE_GROUP_FILE,
+  UPDATE_GROUP_FILE,
+  DELETE_GROUP_FILE,
+  GET_GROUP_FILE,
+  GET_GROUP_FILES,
+  GET_GROUP_FILES_LISTS,
+  GET_GROUP_FEEDBACK_REQUESTED_FILES,
+  ASSIGN_FILE,
+} from "../config";
+
+@Injectable()
+export class GroupFileService {
+  translateService: any;
+
+  /**
+   * Creates a new FileService with the injected HttpClient.
+   * @param {HttpClient} http - The injected HttpClient.
+   * @constructor
+   */
+  constructor(
+    private http: HttpClient,
+    private router: Router,
+    private authService: AuthenticationService,
+    public translate: TranslateService
+  ) {
+    this.translateService = translate;
+  }
+
+  private getHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Authorization: "Bearer " + this.authService.getToken(),
+    });
+  }
+
+  private postHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Accept: "application/json",
+      "Access-Control-Allow-Headers": "Content-Type",
+    });
+  }
+
+  getGroupFile(groupId: number, id: number): Observable<{ file: MFile }> {
+    return this.http
+      .get<{ file: MFile }>(
+        GET_GROUP_FILE.replace(/:group_id/g, String(groupId)).replace(
+          /:id/g,
+          String(id)
+        ),
+        {
+          headers: this.getHeaders(),
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  getSpecificUserFileWithSetGroup(groupId: number, userId: number) {
+    return {
+      getFile: (id: number) => {
+        return this.getSpecificUserGroupFile(groupId, userId, id);
+      },
+    };
+  }
+
+  getGroupFiles(groupId: number): Observable<MFile[]> {
+    return this.http
+      .get<MFile[]>(GET_GROUP_FILES.replace(/:group_id/g, String(groupId)), {
+        headers: this.getHeaders(),
+      })
+      .pipe(catchError(this.handleError));
+  }
+
+  getSpecificUserGroupFiles(
+    groupId: number,
+    userId: number
+  ): Observable<MFile[]> {
+    return this.http
+      .get<MFile[]>(GET_GROUP_FILES.replace(/:group_id/g, String(groupId)), {
+        headers: this.getHeaders(),
+        params: new HttpParams().set("user_id", userId),
+      })
+      .pipe(catchError(this.handleError));
+  }
+
+  getSpecificUserGroupFile(
+    groupId: number,
+    userId: number,
+    fileId: number
+  ): Observable<{ file: MFile }> {
+    return this.http
+      .get<{ file: MFile }>(
+        GET_GROUP_FILE.replace(/:group_id/g, String(groupId)).replace(
+          /:id/g,
+          String(fileId)
+        ),
+        {
+          headers: this.getHeaders(),
+          params: new HttpParams().set("user_id", userId),
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  getGroupFilesList(
+    groupId: number,
+    options = {}
+  ): Observable<{ files: MFile[] }> {
+    const siblingsOfId = options["siblingsOfId"];
+    return this.http
+      .get<{ files: MFile[] }>(
+        GET_GROUP_FILES_LISTS.replace(/:group_id/g, String(groupId)),
+        {
+          headers: this.getHeaders(),
+          params: siblingsOfId
+            ? new HttpParams().set("siblings_of_id", siblingsOfId)
+            : null,
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  getFeedbackRequestedGroupFiles(
+    groupId: number,
+    userId?: number
+  ): Observable<MFile[]> {
+    let params = {};
+    if (userId) {
+      params["user_id"] = userId;
+    }
+    return this.http
+      .get<MFile[]>(
+        GET_GROUP_FEEDBACK_REQUESTED_FILES.replace(
+          /:group_id/g,
+          String(groupId)
+        ),
+        {
+          headers: this.getHeaders(),
+          params: params,
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  createGroupFile(
+    groupId: number,
+    file: MFile
+  ): Observable<HttpResponse<Object>> {
+    return this.http.post<Object>(
+      CREATE_GROUP_FILE.replace(/:group_id/g, String(groupId)),
+      {
+        file: {
+          title: file.title,
+          parent_id: file.parent_id,
+          directory: file.directory,
+        },
+      },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  updateGroupFile(
+    groupId: number,
+    file_id,
+    file_parent_id,
+    users
+  ): Observable<HttpResponse<Object>> {
+    const update_params = {};
+    if (file_parent_id) {
+      update_params["parent_id"] = file_parent_id;
+    }
+    if (users) {
+      users = users.map((user) => {
+        return { ...user, role: user.role.toLowerCase() };
+      });
+      update_params["users"] = users;
+    }
+
+    return this.http.patch<Object>(
+      `${UPDATE_GROUP_FILE.replace(/:group_id/g, String(groupId))}/${file_id}`,
+      { file: update_params },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  requestFeedback(
+    groupId: number,
+    fileId: number
+  ): Observable<HttpResponse<Object>> {
+    return this.http.patch<Object>(
+      `${UPDATE_GROUP_FILE.replace(/:group_id/g, String(groupId))}/${fileId}`,
+      { file: { feedback_requested: true } },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  returnFeedback(
+    groupId: number,
+    fileId: number,
+    userId: number
+  ): Observable<HttpResponse<Object>> {
+    return this.http.patch<Object>(
+      `${UPDATE_GROUP_FILE.replace(/:group_id/g, String(groupId))}/${fileId}`,
+      { file: { feedback_requested: false }, user_id: userId },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  deleteGroupFile(groupId: number, file_id): Observable<HttpResponse<Object>> {
+    return this.http.delete<Object>(
+      `${DELETE_GROUP_FILE.replace(/:group_id/g, String(groupId))}/${file_id}`,
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  assignFile(
+    groupId: number,
+    fileId: number,
+    usersIds,
+    subgroupsIds
+  ): Observable<HttpResponse<Object>> {
+    return this.http.post<Object>(
+      `${ASSIGN_FILE.replace(/:group_id/g, String(groupId)).replace(
+        /:file_id/g,
+        String(fileId)
+      )}`,
+      { assignment: { user_ids: usersIds } },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  /**
+   * Handle HTTP error
+   */
+  private handleError(error: any) {
+    if (error.status == 401) {
+      this.translateService
+        .get("i18n.code")
+        .subscribe((res) => this.router.navigate(["/" + res + "/login"]));
+    }
+    // In a real world app, we might use a remote logging infrastructure
+    // We'd also dig deeper into the error to get a better message
+    let errMsg = error.message
+      ? error.message
+      : error.status
+      ? `${error.status} - ${error.statusText}`
+      : "Server error";
+    console.error(errMsg); // log to console instead
+    return observableThrowError(errMsg);
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/services/group.service.ts b/Frontend Angular 4/src/app/shared/services/group.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..94080d5303dcdc5cd907b2017ca84138ff9c9eee
--- /dev/null
+++ b/Frontend Angular 4/src/app/shared/services/group.service.ts	
@@ -0,0 +1,268 @@
+import { throwError as observableThrowError, Observable } from "rxjs";
+import { Injectable } from "@angular/core";
+import { Router } from "@angular/router";
+import {
+  HttpClient,
+  HttpHeaders,
+  HttpParams,
+  HttpResponse,
+} from "@angular/common/http";
+import { Archivo, Evaluacion, MFile } from "../objects/archivo-types";
+import { Group } from "../objects/grupo";
+
+import { TranslateService } from "@ngx-translate/core";
+import { AuthenticationService } from "./authentication.service";
+import { catchError } from "rxjs/operators";
+import {
+  CREATE_GROUP,
+  UPDATE_GROUP,
+  DELETE_GROUP,
+  GET_GROUP,
+  GET_GROUPS,
+  CREATE_GROUP_FILE_FEEDBACK_REQUEST,
+  GET_GROUP_USER_ROLE,
+} from "../config";
+
+@Injectable()
+export class GroupService {
+  translateService: any;
+
+  /**
+   * Creates a new GroupService with the injected HttpClient.
+   * @param {HttpClient} http - The injected HttpClient.
+   * @constructor
+   */
+  constructor(
+    private http: HttpClient,
+    private router: Router,
+    private authService: AuthenticationService,
+    public translate: TranslateService
+  ) {
+    this.translateService = translate;
+  }
+
+  private getHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Authorization: "Bearer " + this.authService.getToken(),
+    });
+  }
+
+  private postHeaders() {
+    return new HttpHeaders({
+      "Content-Type": "application/json",
+      Accept: "application/json",
+      "Access-Control-Allow-Headers": "Content-Type",
+    });
+  }
+
+  getGroup(id: number): Observable<{ group: Group }> {
+    return this.http
+      .get<{ group: Group }>(GET_GROUP.replace(/:id/g, String(id)), {
+        headers: this.getHeaders(),
+      })
+      .pipe(catchError(this.handleError));
+  }
+
+  getGroups(): Observable<{ groups: Group[] }> {
+    return this.http
+      .get<{ groups: Group[] }>(GET_GROUPS, {
+        headers: this.getHeaders(),
+      })
+      .pipe(catchError(this.handleError));
+  }
+
+  fileToArchivo(file: MFile, parent: Archivo = null): Archivo {
+    let archivo = new Archivo();
+    archivo;
+    archivo.id = file.id;
+    archivo.documentId = file.document_id;
+    archivo.nombre = file.title;
+    archivo.contenido = "";
+    archivo.fechaCreacion = file.created_at;
+    archivo.cedulaCreador = file.users[0]?.email;
+    archivo.editable = true;
+    archivo.padreId =
+      file.ancestry === "/"
+        ? -1
+        : parseInt(file.ancestry.slice(0, -1).split("/").pop());
+    archivo.archivos = [];
+    archivo.parent = parent;
+    archivo.archivoOrigenId = null;
+    archivo.directorio = file.directory;
+    archivo.estado = "activo";
+    archivo.eliminado = false;
+    archivo.evaluacion = null;
+    archivo.users = file.users;
+    archivo.role = file.role;
+
+    if (!!file.children) {
+      archivo.archivos = file.children.map<Archivo>((child) => {
+        return this.fileToArchivo(child, archivo);
+      });
+    }
+
+    return archivo;
+  }
+
+  createGroup(name: string): Observable<HttpResponse<Object>> {
+    return this.http.post<Object>(
+      CREATE_GROUP,
+      {
+        group: {
+          name: name,
+        },
+      },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  archivoToFile(archivo: Archivo, parent: MFile = null): MFile {
+    let file = {
+      id: archivo.id,
+      document_id: archivo.documentId,
+      title: archivo.nombre,
+      created_at: archivo.fechaCreacion,
+      parent_id: archivo.padreId,
+      parent: parent,
+      children: [],
+      directory: archivo.directorio,
+      role: archivo.role,
+    };
+
+    file.children = archivo.archivos.map<MFile>((archivoHijo) => {
+      return this.archivoToFile(archivoHijo, file);
+    });
+
+    return file;
+  }
+
+  completeFiles(file: MFile, parent: MFile = null): MFile {
+    file.parent = parent;
+    file.children.forEach((child) => {
+      this.completeFiles(child, file);
+    });
+
+    return file;
+  }
+
+  filterOnlyDirectories(file: MFile, parent: MFile = null): MFile {
+    let newFile = {
+      id: file.id,
+      document_id: file.document_id,
+      title: file.title,
+      created_at: file.created_at,
+      parent_id: file.parent_id,
+      parent: parent,
+      children: [],
+      directory: file.directory,
+    };
+
+    newFile.children = file.children
+      .filter((child) => child.directory)
+      .map((child) => this.filterOnlyDirectories(child, newFile));
+
+    return newFile;
+  }
+
+  updateGroup(group_id, users): Observable<HttpResponse<Object>> {
+    const update_params = {};
+    if (users) {
+      users = users.map((user) => {
+        return { ...user, role: user.role.toLowerCase() };
+      });
+      update_params["users"] = users;
+    }
+
+    return this.http.patch<Object>(
+      `${UPDATE_GROUP}/${group_id}`,
+      { group: update_params },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  destroyGroup(group_id): Observable<HttpResponse<Object>> {
+    return this.http.delete<Object>(`${DELETE_GROUP}/${group_id}`, {
+      observe: "response",
+      headers: this.postHeaders(),
+    });
+  }
+
+  // destroyAuxFile(): void {
+  //   this.http.delete<Object>(DESTROY_AUX_DOCUMENT, {
+  //     headers: this.postHeaders(),
+  //   });
+  // }
+
+  requestFeedback(
+    groupId: number,
+    fileId: number
+  ): Observable<HttpResponse<Object>> {
+    return this.http.patch<Object>(
+      `${CREATE_GROUP_FILE_FEEDBACK_REQUEST.replace(
+        /:group_id/g,
+        String(groupId)
+      )}`,
+      { feedback_request: { file_id: fileId } },
+      {
+        observe: "response",
+        headers: this.postHeaders(),
+      }
+    );
+  }
+
+  getUserRole(
+    groupId: number,
+    userId: number
+  ): Observable<{ role: { role: string } }> {
+    return this.http
+      .get<{ role: { role: string } }>(
+        GET_GROUP_USER_ROLE.replace(/:group_id/g, String(groupId)).replace(
+          /:user_id/g,
+          String(userId)
+        ),
+        {
+          headers: this.getHeaders(),
+        }
+      )
+      .pipe(catchError(this.handleError));
+  }
+
+  userCanEditAnyGroupFile(role: string): boolean {
+    return role === "owner" || role === "moderator" || role === "manager";
+  }
+
+  userCanReturnFeedback(role: string): boolean {
+    return this.userCanEditAnyGroupFile(role);
+  }
+
+  userCanAssignFiles(role: string): boolean {
+    return this.userCanEditAnyGroupFile(role);
+  }
+
+  /**
+   * Handle HTTP error
+   */
+  private handleError(error: any) {
+    if (error.status == 401) {
+      this.translateService
+        .get("i18n.code")
+        .subscribe((res) => this.router.navigate(["/" + res + "/login"]));
+    }
+    // In a real world app, we might use a remote logging infrastructure
+    // We'd also dig deeper into the error to get a better message
+    let errMsg = error.message
+      ? error.message
+      : error.status
+      ? `${error.status} - ${error.statusText}`
+      : "Server error";
+    console.error(errMsg); // log to console instead
+    return observableThrowError(errMsg);
+  }
+}
diff --git a/Frontend Angular 4/src/app/shared/services/haskell.service.ts b/Frontend Angular 4/src/app/shared/services/haskell.service.ts
index 5702c47ba90041a8411762f8fcfb7410f2927a29..7d086cabe4c056d24bbf7bd7d545ecec83cf511d 100755
--- a/Frontend Angular 4/src/app/shared/services/haskell.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/haskell.service.ts	
@@ -3,7 +3,7 @@ import { Injectable } from "@angular/core";
 import { Router } from "@angular/router";
 import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
 import { Archivo, Evaluacion } from "../objects/archivo-types";
-import { Grupo } from "../objects/grupo";
+import { Group } from "../objects/grupo";
 
 import { SERVER } from "../config";
 import { TranslateService } from "@ngx-translate/core";
@@ -145,14 +145,14 @@ export class HaskellService {
       .pipe(catchError(this.handleError));
   }
 
-  getGrupos(cedula: string): Observable<Grupo[]> {
+  getGrupos(cedula: string): Observable<Group[]> {
     let headers = this.getHeaders();
     let params: HttpParams = new HttpParams();
     params = params.set("cedula", cedula);
     let httpOptions = { headers: headers, params: params };
 
     return this.http
-      .get<Grupo[]>(SERVER + "/servicios/grupo", httpOptions)
+      .get<Group[]>(SERVER + "/servicios/grupo", httpOptions)
       .pipe(catchError(this.handleError));
   }
 
diff --git a/Frontend Angular 4/src/app/shared/services/session.service.ts b/Frontend Angular 4/src/app/shared/services/session.service.ts
index 697c1a7b1678f348e10b1e33464ce0bffe8e8038..4ce6bfbe820c37ca1d024652e539f2ce87a2ee56 100755
--- a/Frontend Angular 4/src/app/shared/services/session.service.ts	
+++ b/Frontend Angular 4/src/app/shared/services/session.service.ts	
@@ -1,6 +1,6 @@
 import { Injectable } from "@angular/core";
 import { Archivo, MFile, MDocument } from "../objects/archivo-types";
-import { Grupo } from "../objects/grupo";
+import { Group } from "../objects/grupo";
 
 @Injectable()
 export class SessionService {
@@ -11,7 +11,7 @@ export class SessionService {
   directorioActual: any;
   archivosCompartidos: any;
   file: MFile;
-  grupos: Grupo[];
+  grupos: Group[];
   currentDirectoryDocuments: MDocument[];
 
   public setArchivo(archivo) {
@@ -40,7 +40,7 @@ export class SessionService {
     return this.file;
   }
 
-  public setGrupos(grupos: Grupo[]) {
+  public setGrupos(grupos: Group[]) {
     this.grupos = grupos;
   }
 
diff --git a/Frontend Angular 4/src/app/shared/shared.module.ts b/Frontend Angular 4/src/app/shared/shared.module.ts
index 73c823e535a89d4010fac0385cded1ebd07c59d7..bf77a6d71358c0605253f44a46192c45ad171555 100644
--- a/Frontend Angular 4/src/app/shared/shared.module.ts	
+++ b/Frontend Angular 4/src/app/shared/shared.module.ts	
@@ -3,19 +3,29 @@ import { MainButtonComponent } from "./components/main-button/main-button.compon
 import { TitleCaseModule } from "../shared/modules/titlecase.module";
 import { I18nModule } from "../shared/modules/translate/i18n.module";
 import { CommonModule } from "@angular/common";
-import { CreateFileModal } from "./components";
-import { ImportFileModal } from "./components";
-import { ShareFileModal } from "./components";
 import { FormsModule } from "@angular/forms";
-import { FolderInput } from "./components";
-import { SelectComponent } from "./components";
-import { ChipInputComponent } from "./components";
 import { MatFormFieldModule } from "@angular/material/form-field";
 import { MatChipsModule } from "@angular/material/chips";
+import { MatCheckboxModule } from "@angular/material/checkbox";
 import { MatIconModule } from "@angular/material/icon";
 import { NgbDropdownModule } from "@ng-bootstrap/ng-bootstrap";
-import { AddUsersModal } from "./components";
-
+import {
+  ActionConfirmationModal,
+  AddUsersModal,
+  ChipInputComponent,
+  CreateFileModal,
+  CreateGroupModal,
+  DestroyGroupModal,
+  FolderInput,
+  ImportFileModal,
+  ManageGroupUsersModal,
+  RequestFeedbackModal,
+  ReturnFeedbackModal,
+  SelectComponent,
+  ShareFileModal,
+  AssignFileModal,
+  CheckboxSelect,
+} from "./components";
 @NgModule({
   imports: [
     TitleCaseModule,
@@ -24,18 +34,27 @@ import { AddUsersModal } from "./components";
     FormsModule,
     MatFormFieldModule,
     MatChipsModule,
+    MatCheckboxModule,
     MatIconModule,
     NgbDropdownModule,
   ],
   declarations: [
     MainButtonComponent,
     CreateFileModal,
+    CreateGroupModal,
     FolderInput,
     ImportFileModal,
     ShareFileModal,
+    ManageGroupUsersModal,
     ChipInputComponent,
     SelectComponent,
     AddUsersModal,
+    ActionConfirmationModal,
+    DestroyGroupModal,
+    RequestFeedbackModal,
+    ReturnFeedbackModal,
+    AssignFileModal,
+    CheckboxSelect,
   ],
   exports: [MainButtonComponent, CreateFileModal],
 })
diff --git a/Frontend Angular 4/src/app/utils.ts b/Frontend Angular 4/src/app/utils.ts
index 35a774c95b5b672d81f2af0339ce32fce0e99512..f66570fd54dde6b1c2dbd8d50540dde5bc00daab 100644
--- a/Frontend Angular 4/src/app/utils.ts	
+++ b/Frontend Angular 4/src/app/utils.ts	
@@ -41,3 +41,11 @@ export function findInTree<T extends MFile | Archivo>(
 export function roleCanShareFile(role: string): boolean {
   return role === "owner" || role === "manager";
 }
+
+export function roleCanManageGroupUsers(role: string): boolean {
+  return role === "owner" || role === "manager";
+}
+
+export function roleCanDestroyGroup(role: string): boolean {
+  return role === "owner";
+}
diff --git a/Frontend Angular 4/src/assets/i18n/en.json b/Frontend Angular 4/src/assets/i18n/en.json
index 75eebe99dd64ca40081fb00774e733c03c7833a8..4f83be6543748af4c0c30382df7fcd0f8394d1f3 100755
--- a/Frontend Angular 4/src/assets/i18n/en.json	
+++ b/Frontend Angular 4/src/assets/i18n/en.json	
@@ -33,7 +33,10 @@
       "close": "close",
       "qualify": "qualify",
       "confirm": "confirm",
-      "signup": "sign up"
+      "signup": "sign up",
+      "requestFeedback": "Request feedback",
+      "returnFeedback": "Return feedback",
+      "assignFile": "Assign file"
     },
     "links": {
       "register": "Create account",
@@ -134,6 +137,10 @@
         "success": "Please check your email",
         "error": "An error occurred while sending the email"
       },
+      "group": {
+        "manageGroupUsers": "Manage group users",
+        "destroyGroupTooltip": "Destroy Group"
+      },
       "updatePassword": {
         "success": "Your password has been updated, you will be redirected shortly",
         "error": "An error occurred while updating your password",
@@ -159,7 +166,9 @@
         "invalidName": "Invalid file name."
       },
       "group": {
-        "select": "Select a group"
+        "select": "Select a group",
+        "capitalLetter": "Group name must start with upper case.",
+        "invalidName": "Invalid group name."
       }
     },
     "shortcuts": {
diff --git a/Frontend Angular 4/src/assets/i18n/es.json b/Frontend Angular 4/src/assets/i18n/es.json
index 55e091b35a0ef601f9dc6ce14d311d6e11884bf2..e7f10863633287a43f8708af28243b4811935495 100755
--- a/Frontend Angular 4/src/assets/i18n/es.json	
+++ b/Frontend Angular 4/src/assets/i18n/es.json	
@@ -33,7 +33,10 @@
       "close": "cerrar",
       "qualify": "calificar",
       "confirm": "confirmar",
-      "signup": "registrarse"
+      "signup": "registrarse",
+      "requestFeedback": "Solicitar retroalimentación",
+      "returnFeedback": "Devolver retroalimentación",
+      "assignFile": "Asignar archivo"
     },
     "links": {
       "register": "Registrarse",
@@ -134,6 +137,10 @@
         "success": "Favor busque en su correo el email",
         "error": "Error al enviar el email"
       },
+      "group": {
+        "manageGroupUsers": "Administrar usuarios del grupo",
+        "destroyGroupTooltip": "Destruir Grupo"
+      },
       "updatePassword": {
         "success": "Su contraseña ha sido actualizada, será redirigido en 5 segundos",
         "error": "Ha ocurrido un error al actualizar su contraseña",
@@ -159,7 +166,9 @@
         "invalidName": "Nombre de archivo inválido."
       },
       "group": {
-        "select": "Seleccione un grupo"
+        "select": "Seleccione un grupo",
+        "capitalLetter": "Nombre del grupo debe iniciar con mayúscula.",
+        "invalidName": "Nombre de grupo inválido."
       }
     },
     "shortcuts": {
diff --git a/Frontend Angular 4/src/styles/console.css b/Frontend Angular 4/src/styles/console.css
index 4a44020d73acfef4efbe3d6f7c30a74e7da9ad84..6441af37415a27b6a41e2ccdf74d9c43630779a4 100755
--- a/Frontend Angular 4/src/styles/console.css	
+++ b/Frontend Angular 4/src/styles/console.css	
@@ -70,7 +70,7 @@
 
 .nomArchivoInp {
   /*width: 55% !important;*/
-  width: calc(100% - 315px);
+  width: calc(100% - 345px);
   float: left;
 }