Skip to content

Commit

Permalink
Agregando los cambios en la UI para permitir cursos recomendados (ome…
Browse files Browse the repository at this point in the history
…gaup#7627)

# Description

En este cambio se agrega todo lo referente a los cambios en la UI para
permitir la configuración de cursos recomendados a los curadores de
cursos.

A continuación se muestra como funcionarán los cursos públicos.

1.- Creando cursos públicos como usuario normal:

![PublicCourseCreateAsNormalUser](https://github.com/user-attachments/assets/2ccdd98d-94af-4620-ac85-d8cd63d8854a)

2.- Permitiendo mostrar el curso en el listado de cursos públicos como
admin:

![PublicCourseDisplayInPublicCoursesListAsAdmin](https://github.com/user-attachments/assets/f35337c0-0d18-49f8-a4ba-bcb1161e9798)

3.- Uniendose a un curso público por medio de un link:

![PublicCourseJoinWithLink](https://github.com/user-attachments/assets/a07285b6-b050-45bf-ba28-f2aa0f7b6bdd)

4.- Uniendose a un curso público que se muestra en el listado de cursos
públicos:

![PublicCourseJoinFromPublicCoursesList](https://github.com/user-attachments/assets/e4c3d8de-bb5c-467b-bad8-07663b060635)


Fixes: omegaup#6842

# Checklist:

- [x] The code follows the [coding
guidelines](https://github.com/omegaup/omegaup/wiki/Coding-guidelines)
of omegaUp.
- [x] The tests were executed and all of them passed.
- [x] If you are creating a feature, the new tests were added.
- [x] If the change is large (> 200 lines), this PR was split into
various Pull Requests. It's preferred to create one PR for changes in
controllers + unit tests in PHPUnit, and then another Pull Request for
UI + tests in Jest, Cypress or both.
  • Loading branch information
pabo99 authored Aug 1, 2024
1 parent 30d4dd2 commit d41bb12
Show file tree
Hide file tree
Showing 23 changed files with 241 additions and 75 deletions.
32 changes: 31 additions & 1 deletion cypress/e2e/course.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
RunOptions,
} from '../support/types';
import { loginPage } from '../support/pageObjects/loginPage';
import { contestPage } from '../support/pageObjects/contestPage';
import { profilePage } from '../support/pageObjects/profilePage';
import getEditorIframeBody from '../support/pageObjects/util';
import { problemPage } from '../support/pageObjects/problemPage';
Expand Down Expand Up @@ -598,4 +597,35 @@ describe('Course Test', () => {
});
cy.logout();
});


it('Should create a public course and share the link to allow joining it', () => {
const loginOptions = loginPage.registerMultipleUsers(2);
const courseOptions = coursePage.generateCourseOptions();
const courseAlias = courseOptions.courseAlias;
const assignmentAlias = 'ut_rank_hw_' + uuid();
const shortAlias = assignmentAlias.slice(0, 12);
const problemOptions = problemPage.generateProblemOptions(1);

cy.login(loginOptions[0]);
cy.createProblem(problemOptions[0]);
coursePage.createCourse(courseOptions);
coursePage.makeCoursePublic();
coursePage.addAssignmentWithProblems(
assignmentAlias,
shortAlias,
problemOptions,
);
cy.logout();

cy.login(loginOptions[1]);
cy.get('a[data-nav-courses]').click();
cy.get('a[data-nav-courses-all]').click();
cy.get('.introjs-skipbutton').click();
const courseUrl = '/course/' + courseAlias;
cy.get(`div>a[href="${courseUrl}"]`, { timeout: 0 }).should('not.exist');
cy.visit(courseUrl);
cy.waitUntil(() => cy.url().should('include', courseUrl));
cy.get('button[name=start-course-submit]').click();
});
});
7 changes: 7 additions & 0 deletions cypress/support/pageObjects/coursePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ export class CoursePage {
cy.url().should('include', `/course/${courseOptions.courseAlias}/edit/`);
}

makeCoursePublic(): void {
cy.get('[data-course-edit-admission-mode]').click();
cy.get('div[data-admission-mode-tab]').should('be.visible');
cy.get('[name="admission-mode"]').select('public');
cy.get('form[data-course-admission-mode-form]').submit();
}

createInvalidSubmission(
problemOptions: ProblemOptions,
runOptions: RunOptions,
Expand Down
1 change: 1 addition & 0 deletions frontend/server/src/Controllers/Contest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4782,6 +4782,7 @@ private static function validateContestCanBePublic(\OmegaUp\DAO\VO\Contests $con
);
}
}

/**
* Update a Contest
*
Expand Down
1 change: 0 additions & 1 deletion frontend/server/src/DAO/Courses.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ public static function getPublicCoursesForTab(): array {
Schools s ON c.school_id = s.school_id
WHERE
c.admission_mode = ? AND
c.finish_time IS NULL AND
c.recommended = 1 AND
c.archived = 0;';

Expand Down
9 changes: 7 additions & 2 deletions frontend/templates/en.lang
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ adminSupportEmailUpdatedSuccessfully = "Email updated successfully"
adminSupportPageNotFound = "Page not found"
adminSupportTypeNewEmail = "Type new email"
admissionModeManualOnly = "Manual only (Add the names of your students' accounts)"
admissionModePublic = "Public (Students enroll from the list of public courses)"
admissionModePublic = "Public (Students enroll just with the course link)"
admissionModeShareURL = "Share URL (Students enroll from the URL)"
aliasAlreadyInUse = "Alias \"%(alias)\" already exists. Please choose a different name."
aliasInUse = "alias already exists. Please choose a different alias."
Expand Down Expand Up @@ -529,6 +529,8 @@ courseEditGroupTeachingAssistant = "Teaching assistant group"
courseEditGroupTeachingAssistantAdded = "Teaching assistant group successfully added."
courseEditGroupTeachingAssistantRemoved = "Teaching assistant group successfully removed."
courseEditGroupTeachingAssistantsEmpty = "No teaching assistant groups"
courseEditRequestSetRecommendedCourse = "If you are interested in having your course appear in the list of public courses, please contact [[email protected]](mailto:[email protected]) indicating the course alias for review."
courseEditShowInPublicCoursesList = "Show in public courses list"
courseEditStudents = "Students"
courseEditTeachingAssistantAddedSuccesfully = "Teaching assistant successfully added"
courseEditTeachingAssistantRemovedSuccesfully = "Teaching assistant successfully removed"
Expand Down Expand Up @@ -1394,7 +1396,10 @@ profileStatisticsWeek = "Week"
profileStatisticsYear = "Year"
profileUnsolvedProblems = "Problems tried (but not solved)"
profileUsername = "Account name"
publicCourseCardMetrics = "%(lessonCount) lessons | %(studentCount) students"
publicCourseCardMetricsLessons = "%(lessonCount) lessons"
publicCourseCardMetricsOneLesson = "1 lesson"
publicCourseCardMetricsOneStudent = "1 student"
publicCourseCardMetricsStudents = "%(studentCount) students"
publicCourseInformationDescription = "On-demand courses that omegaUp offers for free."
publicTagsPlaceholder = "Ex. Recursion, Segment Trees, Binary Search"
qualityFormCongrats = "Congratulations for solving this problem!"
Expand Down
9 changes: 7 additions & 2 deletions frontend/templates/es.lang
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ adminSupportEmailUpdatedSuccessfully = "El correo electrónico se actualizó cor
adminSupportPageNotFound = "Página no encontrada"
adminSupportTypeNewEmail = "Escribe el nuevo correo electrónico"
admissionModeManualOnly = "Manual (Agrega los nombres de las cuentas de tus estudiantes)"
admissionModePublic = "Público (Los estudiantes se inscriben desde la lista de cursos públicos)"
admissionModePublic = "Público (Los estudiantes se inscriben con la liga al curso)"
admissionModeShareURL = "Compartir URL (Los estudiantes se inscriben desde el URL)"
aliasAlreadyInUse = "El alias \"%(alias)\" ya está siendo usado. Por favor elige un nombre distinto."
aliasInUse = "El alias (título corto) ya está siendo usado. Por favor elige un alias distinto."
Expand Down Expand Up @@ -529,6 +529,8 @@ courseEditGroupTeachingAssistant = "Grupo de asistentes de enseñanza"
courseEditGroupTeachingAssistantAdded = "Grupo de asistentes de enseñanza agregado correctamente"
courseEditGroupTeachingAssistantRemoved = "Grupo de asistentes de enseñanza eliminado correctamente"
courseEditGroupTeachingAssistantsEmpty = "No hay grupos de asistentes de enseñanza"
courseEditRequestSetRecommendedCourse = "Si te interesa que tu curso aparezca en la lista de cursos públicos, por favor contacta a [[email protected]](mailto:[email protected]) indicando el alias del curso para someterlo a revisión."
courseEditShowInPublicCoursesList = "Mostrar en la lista de cursos públicos"
courseEditStudents = "Estudiantes"
courseEditTeachingAssistantAddedSuccesfully = "Asistente de enseñanza agregado correctamente"
courseEditTeachingAssistantRemovedSuccesfully = "Asistente de enseñanza eliminado correctamente"
Expand Down Expand Up @@ -1394,7 +1396,10 @@ profileStatisticsWeek = "Semana"
profileStatisticsYear = "Año"
profileUnsolvedProblems = "Problemas intentados (pero no resueltos)"
profileUsername = "Nombre de la cuenta"
publicCourseCardMetrics = "%(lessonCount) lecciones | %(studentCount) estudiantes"
publicCourseCardMetricsLessons = "%(lessonCount) lecciones"
publicCourseCardMetricsOneLesson = "1 lección"
publicCourseCardMetricsOneStudent = "1 estudiante"
publicCourseCardMetricsStudents = "%(studentCount) estudiantes"
publicCourseInformationDescription = "Cursos de programación bajo demanda que omegaUp ofrece de forma gratuita."
publicTagsPlaceholder = "Ej. Recursión, Árboles de segmentos, Búsqueda binaria"
qualityFormCongrats = "¡Felicidades por resolver este problema!"
Expand Down
9 changes: 7 additions & 2 deletions frontend/templates/pseudo.lang

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions frontend/templates/pt.lang
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ adminSupportEmailUpdatedSuccessfully = "Email atualizado com sucesso"
adminSupportPageNotFound = "Página não encontrada"
adminSupportTypeNewEmail = "Digite um novo e-mail"
admissionModeManualOnly = "Manual (Adicionar os nomes das contas dos seus estudantes)"
admissionModePublic = "Público (os alunos se inscrevem na lista de cursos públicos)"
admissionModePublic = "Público (Os alunos se inscrevem apenas com o link do curso)"
admissionModeShareURL = "Compartilhar URL (os alunos se inscrevem na URL)"
aliasAlreadyInUse = "Alias \"%(alias)\" já existe. Por favor, escolha um nome diferente."
aliasInUse = "Alias já existe. Por favor, escolha um alias diferente."
Expand Down Expand Up @@ -529,6 +529,8 @@ courseEditGroupTeachingAssistant = "Grupo de assistente de ensino"
courseEditGroupTeachingAssistantAdded = "Grupo de assistentes de ensino adicionado com sucesso"
courseEditGroupTeachingAssistantRemoved = "Grupo de assistentes de ensino removido com sucesso"
courseEditGroupTeachingAssistantsEmpty = "Não hay grupos de assistentes de ensino"
courseEditRequestSetRecommendedCourse = "Se você estiver interessado em ter seu curso apareça na lista de cursos públicos, entre em contato com [[email protected]](mailto:[email protected]) indicando o alias do curso para revisão."
courseEditShowInPublicCoursesList = "Mostrar na lista de cursos públicos"
courseEditStudents = "Alunos"
courseEditTeachingAssistantAddedSuccesfully = "Assistente de ensino adicionado com sucesso"
courseEditTeachingAssistantRemovedSuccesfully = "Assistente de ensino removido com sucesso"
Expand Down Expand Up @@ -1394,7 +1396,10 @@ profileStatisticsWeek = "Semana"
profileStatisticsYear = "Ano"
profileUnsolvedProblems = "Problemas tentados (mas não resolvidos)"
profileUsername = "Nome da conta"
publicCourseCardMetrics = "%(lessonCount) lições | %(studentCount) estudantes"
publicCourseCardMetricsLessons = "%(lessonCount) lições"
publicCourseCardMetricsOneLesson = "1 lição"
publicCourseCardMetricsOneStudent = "1 estudante"
publicCourseCardMetricsStudents = "%(studentCount) estudantes"
publicCourseInformationDescription = "Cursos sob demanda que o omegaUp oferece gratuitamente."
publicTagsPlaceholder = "Ex. Recursão, Árvore de segmentos, Pesquisa Binária"
qualityFormCongrats = "Parabéns por resolver esta problema!"
Expand Down
2 changes: 1 addition & 1 deletion frontend/www/js/omegaup/components/common/Publish.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export enum AdmissionMode {
'font-awesome-layers-text': FontAwesomeLayersText,
},
})
export default class Publish extends Vue {
export default class ContestEditPublish extends Vue {
@Prop() admissionMode!: AdmissionMode;
@Prop() admissionModeDescription!: string;
@Prop() alias!: string;
Expand Down
19 changes: 12 additions & 7 deletions frontend/www/js/omegaup/components/course/AdmissionMode.test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Clipboard from 'v-clipboard';

import T from '../../lang';

import course_AdmissionMode from './AdmissionMode.vue';
import { AdmissionMode } from '../common/Publish.vue';

describe('AdmissionMode.vue', () => {
const localVue = createLocalVue();
Vue.use(Clipboard);

it('Should handle admission mode as curator', () => {
const wrapper = shallowMount(course_AdmissionMode, {
const wrapper = mount(course_AdmissionMode, {
localVue,
propsData: {
admissionModeDescription: T.contestNewFormAdmissionModeDescription,
courseAlias: 'DP',
initialAdmissionMode: 'private',
admissionMode: AdmissionMode.Public,
shouldShowPublicOption: true,
},
});

expect(wrapper.find('select[name="admission-mode"]').text()).toContain(
T.admissionModePublic,
);

expect(
wrapper.find('div[data-toggle-public-course-list]>label').text(),
).toBe(T.courseEditShowInPublicCoursesList);
});

it('Should handle admission mode as normal user', () => {
Expand All @@ -32,13 +37,13 @@ describe('AdmissionMode.vue', () => {
propsData: {
admissionModeDescription: T.contestNewFormAdmissionModeDescription,
courseAlias: 'DP',
initialAdmissionMode: 'private',
admissionMode: AdmissionMode.Public,
shouldShowPublicOption: false,
},
});

expect(wrapper.find('select[name="admission-mode"]').text()).not.toContain(
T.admissionModePublic,
);
expect(
wrapper.find('div[data-toggle-public-course-list]>label').exists(),
).toBeFalsy();
});
});
79 changes: 58 additions & 21 deletions frontend/www/js/omegaup/components/course/AdmissionMode.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<template>
<div class="card">
<div class="card-body">
<form class="publish-form" @submit.prevent="onSubmit">
<form
class="publish-form"
data-course-admission-mode-form
@submit.prevent="onSubmit"
>
<div class="form-group">
<label>{{ T.courseEditAdmissionModeSelect }}</label>
<a
Expand All @@ -11,22 +15,30 @@
>
<img src="/media/question.png" />
</a>
<select
v-model="admissionMode"
class="form-control"
name="admission-mode"
<div class="form-group">
<select
v-model="currentAdmissionMode"
class="form-control"
name="admission-mode"
>
<option :value="AdmissionMode.Private">
{{ T.admissionModeManualOnly }}
</option>
<option :value="AdmissionMode.Registration">
{{ T.admissionModeShareURL }}
</option>
<option :value="AdmissionMode.Public">
{{ T.admissionModePublic }}
</option>
</select>
</div>
<div
v-if="
currentAdmissionMode === AdmissionMode.Registration ||
currentAdmissionMode === AdmissionMode.Public
"
class="form-group"
>
<option value="private">
{{ T.admissionModeManualOnly }}
</option>
<option value="registration">
{{ T.admissionModeShareURL }}
</option>
<option v-if="shouldShowPublicOption" value="public">
{{ T.admissionModePublic }}
</option>
</select>
<div v-show="admissionMode === 'registration'" class="form-group">
<input
class="form-control mb-2 mt-2"
type="text"
Expand All @@ -52,6 +64,22 @@
</span>
</div>
</div>
<div
v-if="currentAdmissionMode === AdmissionMode.Public"
class="form-group"
data-toggle-public-course-list
>
<omegaup-toggle-switch
v-if="shouldShowPublicOption"
:value.sync="currentShowInPublicCoursesList"
:checked-value="currentShowInPublicCoursesList"
:text-description="T.courseEditShowInPublicCoursesList"
></omegaup-toggle-switch>
<omegaup-markdown
v-else
:markdown="T.courseEditRequestSetRecommendedCourse"
></omegaup-markdown>
</div>
</div>
<div class="text-right">
<button class="btn btn-primary change-admission-mode" type="submit">
Expand All @@ -68,6 +96,8 @@ import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import Clipboard from 'v-clipboard';
import T from '../../lang';
import omegaup_Markdown from '../Markdown.vue';
import omegaup_ToggleSwitch from '../ToggleSwitch.vue';
import { AdmissionMode } from '../common/Publish.vue';
import {
FontAwesomeIcon,
Expand All @@ -85,29 +115,36 @@ Vue.use(Clipboard);
'font-awesome-layers': FontAwesomeLayers,
'font-awesome-layers-text': FontAwesomeLayersText,
'omegaup-markdown': omegaup_Markdown,
'omegaup-toggle-switch': omegaup_ToggleSwitch,
},
})
export default class CourseAdmissionMode extends Vue {
@Prop() initialAdmissionMode!: string;
@Prop() admissionMode!: AdmissionMode;
@Prop() courseAlias!: string;
@Prop() shouldShowPublicOption!: boolean;
@Prop({ default: false }) showInPublicCoursesList!: boolean;
T = T;
admissionMode = this.initialAdmissionMode;
AdmissionMode = AdmissionMode;
currentAdmissionMode = this.admissionMode;
currentShowInPublicCoursesList = this.showInPublicCoursesList;
copiedToClipboard = false;
onSubmit(): void {
this.$emit('emit-update-admission-mode', this.admissionMode);
this.$emit('update-admission-mode', {
admissionMode: this.currentAdmissionMode,
showInPublicCoursesList: this.currentShowInPublicCoursesList,
});
}
@Watch('copiedToClipboard')
onPropertyChanged(): void {
setTimeout(() => (this.copiedToClipboard = false), 5000);
}
@Watch('initialAdmissionMode')
@Watch('admissionMode')
onCourseChange(): void {
this.admissionMode = this.initialAdmissionMode;
this.currentAdmissionMode = this.admissionMode;
}
get courseURL(): string {
Expand Down
Loading

0 comments on commit d41bb12

Please sign in to comment.