Skip to content

Commit

Permalink
[@dhealthdapps/backend] feat(routes): add revoke route for providers
Browse files Browse the repository at this point in the history
  • Loading branch information
kravchenkodhealth committed Jan 13, 2023
1 parent 94cea36 commit fa31fdb
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 19 deletions.
35 changes: 35 additions & 0 deletions runtime/backend/src/oauth/routes/OAuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
HttpException,
UseGuards,
HttpStatus,
Delete,
} from "@nestjs/common";
import {
ApiExtraModels,
Expand Down Expand Up @@ -209,6 +210,40 @@ export class OAuthController {
}
}

/**
* Revoke existing integration with passed provider.
*
* @method DELETE
* @param req
* @param provider
* @param query
* @returns
*/
@UseGuards(AuthGuard)
@Delete("oauth/:provider/revoke")
@ApiOperation({
summary: "Remove existing integration",
description: "Remove existing provider from integrations",
})
@ApiExtraModels(OAuthCallbackRequest, StatusDTO)
@ApiOkResponse(HTTPResponses.OAuthLinkResponseSchema)
protected async revoke(
@NestRequest() req: Request,
@Param("provider") provider: string,
@Query() query: OAuthCallbackRequest,
) {
// read and decode access token, then find account in database
const account: AccountDocument = await this.authService.getAccount(req);
try {
return await this.oauthService.deleteIntegration(
provider,
account.address,
);
} catch (e) {
throw e;
}
}

/**
* Requests a user's profile information. This endpoint is
* protected and a valid access token must be attached in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@

@include devices(laptop) {
max-width: 147px;
font-size: 16px;
background-color: #fff;
}

@include devices(mobile) {
font-size: 15px;
background-color: #fff;
}

svg {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ export class HttpRequestHandler implements RequestHandler {
});
}

if (method === "DELETE") {
return axios.delete(url, {
...options,
headers,
});
}

// GET requests are supported
return axios.get(url, {
...options,
Expand Down
18 changes: 18 additions & 0 deletions runtime/dapp-frontend-vue/src/services/IntegrationsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,22 @@ export class IntegrationsService extends BackendService {
{} // no-headers
);
}

/**
*
* @param params
* @returns
*/
public async revoke(provider: string) {
return await this.handler.call(
this.getUrl(`oauth/${provider}/revoke`),
"DELETE",
undefined, // no-body
{
withCredentials: true,
credentials: "include",
},
{} // no-headers
);
}
}
19 changes: 9 additions & 10 deletions runtime/dapp-frontend-vue/src/state/store/OAuthModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,15 @@ export const OAuthModule = {
/**
*
*/
deauthorize(context: OAuthModuleContext, provider: string): void {
// reads current state of "integrations"
const integrations = context.state.integrations;

// removes the integration and mutates
if (integrations.length && integrations.includes(provider)) {
context.commit(
"setIntegrations",
integrations.filter((i) => i !== provider)
);
async revoke(context: OAuthModuleContext, provider: string): Promise<void> {
const service = new IntegrationsService();
try {
// strava is the only provider currently
await service.revoke(provider);
await context.dispatch("auth/fetchProfile", "", { root: true });
} catch (e) {
console.log("oauth/revoke", e);
throw e;
}
},
},
Expand Down
21 changes: 20 additions & 1 deletion runtime/dapp-frontend-vue/src/views/Settings/Settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,26 @@
.setting {
padding: 16px 32px;
border-bottom: 1px solid #b2b3c9;
cursor: pointer;
position: relative;

&:hover {
.remove-integration {
display: inline-block;
}
}

.remove-integration {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
cursor: pointer;
display: none;

path {
fill: $system-grey-60;
}
}

.content {
img {
Expand Down
16 changes: 14 additions & 2 deletions runtime/dapp-frontend-vue/src/views/Settings/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// external dependencies
import { Component } from "vue-property-decorator";
import { mapGetters } from "vuex";
import InlineSvg from "vue-inline-svg";

// internal dependencies
import { MetaView } from "@/views/MetaView";
Expand All @@ -21,6 +22,7 @@ import "./Settings.scss";
@Component({
components: {
UiButton,
InlineSvg,
},
computed: {
...mapGetters({
Expand Down Expand Up @@ -75,7 +77,17 @@ export default class Settings extends MetaView {
* @access protected
* @returns {any}
*/
protected removeIntegration(provider: string) {
this.$store.dispatch("oauth/deauthorize", provider);
protected async removeIntegration(provider: string) {
try {
await this.$store.dispatch("oauth/revoke", provider);
} catch (e) {
this.$root.$emit("toast", {
title: "Error!",
description: `Request failed`,
state: "error",
icon: "icons/close-icon.svg",
dismissTimeout: 7000,
});
}
}
}
7 changes: 6 additions & 1 deletion runtime/dapp-frontend-vue/src/views/Settings/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@
v-for="(integration, index) in getIntegrations"
:key="integration + index"
class="setting"
@click="removeIntegration(integration.id)"
>
<inline-svg
:src="getImageUrl('icons/close-icon.svg')"
:width="24"
class="remove-integration"
@click="removeIntegration(integration)"
/>
<div class="container text-left">
<div class="text-left flex flex-row justify-between items-center">
<div class="content flex flex-row items-center">
Expand Down

0 comments on commit fa31fdb

Please sign in to comment.