Skip to content

Commit

Permalink
Fix part of #19435: Migrate Email Dashboard (#19627)
Browse files Browse the repository at this point in the history
* email dashboard page added among the pages registered with frontend

* handler for email dashboard removed from backend

* removed backend test for email dashbard page

* removed link with old handler

* redundant mainpage file deleted

* added auth guard for email dashboard

* removed downgrading of email dashboard page

* added root component for email dashboard

* updated module for email dashboard

* added to the app routing module

* removed email dashboard module from webpack configuration

* fixed linter errors

* linter checks fixed

* navbar added to the email dashboard page

* test added for auth guard and root component of email dashboard

* removed redundant backend test case as the page is migrated to frontend

* added css to the root page component

* style moved to the top to follow the existing standard

* updated 2023 to 2024 in copyright disclaimer

* updated test description
  • Loading branch information
sagar-subedi committed Feb 12, 2024
1 parent 2eb298f commit fe15ab8
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 162 deletions.
18 changes: 18 additions & 0 deletions assets/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6602,6 +6602,24 @@ export default {
}
]
},
"EMAIL_DASHBOARD": {
"ROUTE": "emaildashboard",
"TITLE": "Email Dashboard - Oppia",
"META": [
{
"PROPERTY_TYPE": "itemprop",
"PROPERTY_VALUE": "description",
// eslint-disable-next-line max-len
"CONTENT": "With Oppia, you can access free lessons on math, physics, statistics, chemistry, music, history and more from anywhere in the world. Oppia is a nonprofit with the mission of providing high-quality education to those who lack access to it."
},
{
"PROPERTY_TYPE": "itemprop",
"PROPERTY_VALUE": "og:description",
// eslint-disable-next-line max-len
"CONTENT": "With Oppia, you can access free lessons on math, physics, statistics, chemistry, music, history and more from anywhere in the world. Oppia is a nonprofit with the mission of providing high-quality education to those who lack access to it."
}
]
},
"MODERATOR": {
"ROUTE": "moderator",
"TITLE": "Moderator Tools - Oppia",
Expand Down
14 changes: 0 additions & 14 deletions core/controllers/email_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,6 @@ class UserQueryDict(TypedDict):
num_qualified_users: int


class EmailDashboardPage(
base.BaseHandler[Dict[str, str], Dict[str, str]]
):
"""Page to submit query and show past queries."""

URL_PATH_ARGS_SCHEMAS: Dict[str, str] = {}
HANDLER_ARGS_SCHEMAS: Dict[str, Dict[str, str]] = {'GET': {}}

@acl_decorators.can_manage_email_dashboard
def get(self) -> None:
"""Handles GET requests."""
self.render_template('email-dashboard-page.mainpage.html')


def _generate_user_query_dicts(
user_queries: List[user_query_domain.UserQuery]
) -> List[UserQueryDict]:
Expand Down
18 changes: 0 additions & 18 deletions core/controllers/email_dashboard_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,6 @@ def test_query_status_check_handler(self) -> None:

self.logout()

def test_that_page_is_accessible_to_authorised_users_only(self) -> None:
# Make sure that only authorised users can access query pages.
self.login(self.USER_A_EMAIL)
with self.assertRaisesRegex(Exception, '401 Unauthorized'):
self.get_html_response('/emaildashboard')
with self.assertRaisesRegex(Exception, '401 Unauthorized'):
self.get_html_response(
'/querystatuscheck?query_id=%s' % 'valid_query_id')
self.logout()

def test_that_exception_is_raised_for_invalid_input(self) -> None:
self.login(self.SUBMITTER_EMAIL, is_super_admin=True)
csrf_token = self.get_new_csrf_token()
Expand Down Expand Up @@ -128,14 +118,6 @@ def test_starting_job(self) -> None:

self.logout()

def test_email_dashboard_page(self) -> None:
self.login(self.SUBMITTER_EMAIL, is_super_admin=True)

response = self.get_html_response('/emaildashboard')
self.assertIn(b'{"title": "Email Dashboard - Oppia"})', response.body)

self.logout()


class EmailDashboardResultTests(test_utils.EmailTestBase):
"""Tests for email dashboard result handler."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2024 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Tests for EmailDashboardAuthGuard
*/

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot, NavigationExtras } from '@angular/router';

import { AppConstants } from '../../app.constants';
import { UserInfo } from '../../domain/user/user-info.model';
import { UserService } from '../../services/user.service';
import { EmailDashboardAuthGuard } from './email-dashboard-auth.guard';


class MockRouter {
navigate(commands: string[], extras?: NavigationExtras): Promise<boolean> {
return Promise.resolve(true);
}
}

describe('EmailDashboardAuthGuard', () => {
let userService: UserService;
let router: Router;
let guard: EmailDashboardAuthGuard;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [UserService, { provide: Router, useClass: MockRouter }],
}).compileComponents();

guard = TestBed.inject(EmailDashboardAuthGuard);
userService = TestBed.inject(UserService);
router = TestBed.inject(Router);
});

it('should redirect to 401 page if user is not super admin', (done) => {
const getUserInfoAsyncSpy = spyOn(
userService, 'getUserInfoAsync').and.returnValue(
Promise.resolve(UserInfo.createDefault())
);
const navigateSpy = spyOn(router, 'navigate').and.callThrough();

guard.canActivate(
new ActivatedRouteSnapshot(), {} as RouterStateSnapshot).then(
(canActivate) => {
expect(canActivate).toBeFalse();
expect(getUserInfoAsyncSpy).toHaveBeenCalledTimes(1);
expect(navigateSpy).toHaveBeenCalledWith([
`${AppConstants.PAGES_REGISTERED_WITH_FRONTEND.ERROR.ROUTE}/401`]);
done();
});
});

it('should access the email dashboard if the user is super admin', (done) => {
const getUserInfoAsyncSpy = spyOn(
userService, 'getUserInfoAsync').and.returnValue(
Promise.resolve(new UserInfo(
[], false, false, true, false, false, '', '', '', true))
);
const navigateSpy = spyOn(router, 'navigate').and.callThrough();

guard.canActivate(
new ActivatedRouteSnapshot(), {} as RouterStateSnapshot).then(
(canActivate) => {
expect(canActivate).toBeTrue();
expect(getUserInfoAsyncSpy).toHaveBeenCalledTimes(1);
expect(navigateSpy).not.toHaveBeenCalled();
done();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2024 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Guard that redirects user to 401 error page
* if the user is not a super admin.
*/

import { Location } from '@angular/common';
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot,
} from '@angular/router';

import { AppConstants } from 'app.constants';
import { UserService } from 'services/user.service';

@Injectable({
providedIn: 'root'
})
export class EmailDashboardAuthGuard implements CanActivate {
constructor(
private userService: UserService,
private router: Router,
private location: Location
) {}

async canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Promise<boolean> {
const userInfo = await this.userService.getUserInfoAsync();
if (userInfo.isSuperAdmin()) {
return true;
}

this.router.navigate(
[`${AppConstants.PAGES_REGISTERED_WITH_FRONTEND
.ERROR.ROUTE}/401`]).then(() => {
this.location.replaceState(state.url);
});
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<style>
.success {
color: #00f;
}

.oppia-query-form {
text-align: center;
}
</style>
<oppia-angular-root>
<oppia-base-content>
<navbar-breadcrumb>
<ul class="nav navbar-nav oppia-navbar-breadcrumb">
<li>
<span class="oppia-navbar-breadcrumb-separator"></span>
Email Dashboard
</li>
</ul>
</navbar-breadcrumb>
<content>
<oppia-email-dashboard-page></oppia-email-dashboard-page>
</content>
<page-footer></page-footer>
</oppia-base-content>
</oppia-angular-root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2024 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Unit tests for Email Dashboard Page Root component.
*/

import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';

import { AppConstants } from '../../app.constants';
import { PageHeadService } from '../../services/page-head.service';
import { EmailDashboardPageRootComponent } from './email-dashboard-page-root.component';

describe('EmailDashboardPageRootComponent', () => {
let fixture: ComponentFixture<EmailDashboardPageRootComponent>;
let component: EmailDashboardPageRootComponent;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), HttpClientTestingModule],
declarations: [EmailDashboardPageRootComponent],
providers: [PageHeadService],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();

fixture = TestBed.createComponent(EmailDashboardPageRootComponent);
component = fixture.componentInstance;
});

it('should have the title and meta tags set', () => {
expect(component.title).toEqual(
AppConstants.PAGES_REGISTERED_WITH_FRONTEND.EMAIL_DASHBOARD.TITLE);
expect(component.meta).toEqual(
AppConstants.PAGES_REGISTERED_WITH_FRONTEND.EMAIL_DASHBOARD.META);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2024 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
* @fileoverview Email Dashboard page root component.
*/

import { Component } from '@angular/core';
import { AppConstants } from 'app.constants';
import { BaseRootComponent, MetaTagData } from 'pages/base-root.component';

@Component({
selector: 'oppia-email-dashboard-page-root',
templateUrl: './email-dashboard-page-root.component.html',
})
export class EmailDashboardPageRootComponent extends BaseRootComponent {
title: string =
AppConstants.PAGES_REGISTERED_WITH_FRONTEND.EMAIL_DASHBOARD.TITLE;

meta: MetaTagData[] =
AppConstants.PAGES_REGISTERED_WITH_FRONTEND.EMAIL_DASHBOARD.META as
unknown as Readonly<MetaTagData>[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
*/

import { ChangeDetectorRef, Component } from '@angular/core';
import { downgradeComponent } from '@angular/upgrade/static';
import { AppConstants } from 'app.constants';
import { QueryData } from 'domain/email-dashboard/email-dashboard-backend-api.service';
import { EmailDashboardQuery } from 'domain/email-dashboard/email-dashboard-query.model';
Expand Down Expand Up @@ -131,8 +130,3 @@ export class EmailDashboardPageComponent {
return (submitter === this.username) && (status === 'completed');
}
}

angular.module('oppia').directive('oppiaEmailDashboardPage',
downgradeComponent({
component: EmailDashboardPageComponent
}) as angular.IDirectiveFactory);

This file was deleted.

Loading

0 comments on commit fe15ab8

Please sign in to comment.