Skip to content

Commit

Permalink
Merge pull request #40 from velrest/authentication
Browse files Browse the repository at this point in the history
feat(authentication): implement a login modal for the gwr api
  • Loading branch information
velrest authored Apr 12, 2021
2 parents 6cbf10d + 9ea9f40 commit eca5b71
Show file tree
Hide file tree
Showing 23 changed files with 399 additions and 209 deletions.
50 changes: 50 additions & 0 deletions addon/components/login-modal.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<UkModal
@visible={{this.authFetch.showAuthModal}}
@btnClose={{false}}
@escClose={{false}}
@bgClose={{false}}
@container="#ember-ebau-gwr-modal-container" as |Modal|
>
<Modal.header>
<h2 class="uk-modal-title">
{{t "ember-gwr.components.loginModal.header"}}
</h2>
</Modal.header>
<Modal.body>
<div class="uk-grid-small" uk-grid>
<div class="uk-width-1-2">
<input
name="username"
class="uk-input"
placeholder={{t "ember-gwr.components.loginModal.username"}}
value={{this.username}}
{{on "input" this.updateValue}}
/>
</div>
<div class="uk-width-1-2">
<input
name="password"
type="password"
class="uk-input"
placeholder={{t "ember-gwr.components.loginModal.password"}}
value={{this.password}}
{{on "input" this.updateValue}}
/>
</div>
</div>
</Modal.body>
<Modal.footer @class="uk-text-right">
<UkButton
@color="primary"
@disabled={{not (and this.username this.password)}}
@loading={{this.authFetch.housingStatToken.isRunning}}
{{on "click" this.login}}
>
{{t "ember-gwr.components.loginModal.login"}}
</UkButton>
</Modal.footer>
</UkModal>

{{#unless this.authFetch.showAuthModal}}
{{yield}}
{{/unless}}
27 changes: 27 additions & 0 deletions addon/components/login-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";

export default class LoginModalComponent extends Component {
@service authFetch;

@tracked username = "";
@tracked password = "";

@action
async login() {
const token = await this.authFetch.housingStatToken.perform(
this.username,
this.password
);
if (token) {
this.authFetch.showAuthModal = false;
}
}

@action
updateValue({ target: { name, value } = {} }) {
this[name] = value;
}
}
8 changes: 4 additions & 4 deletions addon/controllers/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { inject as service } from "@ember/service";
export default class ProjectController extends Controller {
@service router;
@service store;
@service constructionProject;
@service gwr;

get displayLandingPage() {
return (
Expand All @@ -18,14 +18,14 @@ export default class ProjectController extends Controller {
}

get projects() {
return this.constructionProject.projects;
return this.gwr.projects;
}

@action
async onLoad() {
// We then use `constructionProject.projects` in the template to reference this.
// We then use `gwr.projects` in the template to reference this.
// This is so we can update the table if we add a new project in the subroute /new
const projects = await this.constructionProject.all.perform(this.model);
const projects = await this.gwr.all.perform(this.model);

// Load the first project in the list if none is selected so we always display a project.
if (
Expand Down
10 changes: 5 additions & 5 deletions addon/controllers/project/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Options from "ember-ebau-gwr/models/options";
export default class ProjectFormController extends Controller {
queryParams = ["import"];

@service constructionProject;
@service gwr;
@service config;
@service dataImport;
@service store;
Expand All @@ -27,7 +27,7 @@ export default class ProjectFormController extends Controller {
*fetchProject() {
return this.model.project?.isNew
? this.model.project
: yield this.constructionProject.getFromCacheOrApi(this.model.projectId);
: yield this.gwr.getFromCacheOrApi(this.model.projectId);
}

@lastValue("fetchCalumaData") importData;
Expand Down Expand Up @@ -59,17 +59,17 @@ export default class ProjectFormController extends Controller {
@action
async saveProject() {
if (this.project.isNew) {
const project = await this.constructionProject.create(this.project);
const project = await this.gwr.create(this.project);
const link = this.store.createRecord("gwr-link", {
eproid: project.EPROID,
localId: this.model.instanceId,
});
await link.save();
// Reload the overview table to display the new project
await this.constructionProject.all.perform(this.model.instanceId);
await this.gwr.all.perform(this.model.instanceId);
this.transitionToRoute("project.form", project.EPROID);
} else {
await this.constructionProject.update(this.project);
await this.gwr.update(this.project);
}
this.import = false;
}
Expand Down
11 changes: 3 additions & 8 deletions addon/controllers/project/linked-buildings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { inject as service } from "@ember/service";
import { task } from "ember-concurrency-decorators";

export default class ProjectLinkedBuildingsController extends Controller {
@service constructionProject;
@service gwr;

@task
*fetchBuildings() {
try {
const project = yield this.constructionProject.getFromCacheOrApi(
this.model
);
const project = yield this.gwr.getFromCacheOrApi(this.model);
return project.work;
} catch (error) {
console.error(error);
Expand All @@ -22,10 +20,7 @@ export default class ProjectLinkedBuildingsController extends Controller {
@action
async removeBuildingLink({ building: { EGID } }) {
try {
await this.constructionProject.unbindBuildingFromConstructionProject(
this.model,
EGID
);
await this.gwr.unbindBuildingFromConstructionProject(this.model, EGID);
await this.fetchBuildings.perform();
} catch (error) {
console.error(error);
Expand Down
6 changes: 3 additions & 3 deletions addon/controllers/search-building.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "ember-ebau-gwr/models/options";

export default class SearchBuildingController extends Controller {
@service constructionProject;
@service gwr;
@service config;
@service intl;
@service notification;
Expand All @@ -23,7 +23,7 @@ export default class SearchBuildingController extends Controller {
try {
query.streetLang = languageOptions[this.intl.primaryLocale];
query.municipality = this.config.municipalityId;
return yield this.constructionProject.searchBuilding(query);
return yield this.gwr.searchBuilding(query);
} catch (error) {
console.error(error);
this.notification.danger("ember-gwr.searchBuilding.searchError");
Expand All @@ -32,7 +32,7 @@ export default class SearchBuildingController extends Controller {

@task *linkBuilding(EGID, buildingWork) {
try {
yield this.constructionProject.bindBuildingToConstructionProject(
yield this.gwr.bindBuildingToConstructionProject(
this.model,
EGID,
buildingWork
Expand Down
4 changes: 2 additions & 2 deletions addon/controllers/search-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { task, lastValue } from "ember-concurrency-decorators";
import { projectStatusOptions } from "ember-ebau-gwr/models/options";

export default class SearchProjectController extends Controller {
@service constructionProject;
@service gwr;
@service intl;
@service config;
@service store;
Expand All @@ -20,7 +20,7 @@ export default class SearchProjectController extends Controller {
@task
*search(query = {}) {
query.constructionSurveyDeptNumber = this.config.constructionSurveyDeptNumber;
return yield this.constructionProject.searchProject(query);
return yield this.gwr.searchProject(query);
}

@action
Expand Down
3 changes: 0 additions & 3 deletions addon/routes/project/form.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import Route from "@ember/routing/route";
import { inject as service } from "@ember/service";

export default class ProjectFormRoute extends Route {
@service constructionProject;

async model({ project_id: projectId }) {
return {
projectId,
Expand Down
73 changes: 73 additions & 0 deletions addon/services/auth-fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Service, { inject as service } from "@ember/service";
import { tracked } from "@glimmer/tracking";
import { task, lastValue } from "ember-concurrency-decorators";

export default class AuthFetchService extends Service {
@service config;
@service intl;
@service notification;

@tracked showAuthModal = false;

constructor(...args) {
super(...args);
this.housingStatToken.perform();
}

@lastValue("housingStatToken") token;
@task
*housingStatToken(username, password) {
const response = yield fetch(`/api/v1/housing-stat-token`, {
method: "post",
headers: {
"content-type": "application/json",
},
...(username && password
? {
body: JSON.stringify({
username,
password,
}),
}
: {}),
});

const json = yield response.json();

if (!response.ok) {
if (json["400"]?.source === "internal") {
this.showAuthModal = true;
}

if (json["401"]?.source === "external") {
this.notification.danger(
this.intl.t("ember-gwr.authentication.loginError")
);
this.showAuthModal = true;
}
}

return json.token;
}

async fetch(url, { method = "get", headers = {}, body } = {}, retry = false) {
if (this.housingStatToken.isRunning) {
await this.housingStatToken.lastRunning;
}
let response = await fetch(`${this.config.gwrAPI}${url}`, {
method,
headers: {
token: this.token,
...headers,
},
body,
});
if (!response.ok && response.status === 401 && !this.showAuthModal) {
if (!retry) {
await this.housingStatToken.perform();
response = await this.fetch(url, { method, headers, body }, false);
}
}
return response;
}
}
Loading

0 comments on commit eca5b71

Please sign in to comment.