Add app info dialog

This commit is contained in:
Dominik Korsa 2021-01-22 20:31:58 +01:00
parent 3c1f07f3b0
commit 3992429236
No known key found for this signature in database
GPG key ID: 546F986F71A6FE6E
15 changed files with 254 additions and 3 deletions

View file

@ -1412,6 +1412,14 @@
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
}, },
"cross-fetch": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz",
"integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==",
"requires": {
"node-fetch": "2.6.1"
}
},
"cross-spawn": { "cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -2056,6 +2064,11 @@
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
}, },
"extract-files": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
"integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ=="
},
"fast-decode-uri-component": { "fast-decode-uri-component": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
@ -2484,6 +2497,16 @@
"lodash.get": "^4.4.2" "lodash.get": "^4.4.2"
} }
}, },
"graphql-request": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-3.4.0.tgz",
"integrity": "sha512-acrTzidSlwAj8wBNO7Q/UQHS8T+z5qRGquCQRv9J1InwR01BBWV9ObnoE+JS5nCCEj8wSGS0yrDXVDoRiKZuOg==",
"requires": {
"cross-fetch": "^3.0.6",
"extract-files": "^9.0.0",
"form-data": "^3.0.0"
}
},
"graphql-subscriptions": { "graphql-subscriptions": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.1.0.tgz", "resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.1.0.tgz",

View file

@ -27,6 +27,8 @@
"fastify-sensible": "^3.1.0", "fastify-sensible": "^3.1.0",
"fastify-session": "^5.2.1", "fastify-session": "^5.2.1",
"got": "^11.8.1", "got": "^11.8.1",
"graphql-request": "^3.4.0",
"graphql-tag": "^2.11.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"mongodb": "^3.6.3", "mongodb": "^3.6.3",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",

View file

@ -28,6 +28,12 @@ export default class Application extends BaseEntity {
@Column() @Column()
public redirectUris!: string[]; public redirectUris!: string[];
@Column()
public ownerGitHubLogin!: string;
@Column()
public homepage!: string | null;
public static generateClientId(): string { public static generateClientId(): string {
return nanoid(12); return nanoid(12);
} }

View file

@ -0,0 +1,20 @@
import gql from 'graphql-tag';
export const getUserQuery = gql`query GetUser($login: String!) {
user(login: $login) {
login
name
url
}
}
`;
export interface User {
login: string;
name: string | null;
url: string;
}
export interface GetUserQueryResult {
user: User
}

View file

@ -0,0 +1,14 @@
import { GraphQLClient } from 'graphql-request';
import { requireEnv } from '../../utils';
import type { GetUserQueryResult, User } from './queries/get-user';
import { getUserQuery } from './queries/get-user';
const client = new GraphQLClient('https://api.github.com/graphql');
client.setHeader('Authorization', `bearer ${requireEnv('GITHUB_API_TOKEN')}`);
export async function getUser(login: string): Promise<User> {
const { user } = await client.request<GetUserQueryResult>(getUserQuery, {
login,
});
return user;
}

View file

@ -0,0 +1,15 @@
import { Field, ObjectType } from 'type-graphql';
@ObjectType()
export default class GitHubUser {
@Field(() => String)
public login!: string;
@Field(() => String, {
nullable: true,
})
public name!: string | null;
@Field(() => String)
public url!: string;
}

View file

@ -1,4 +1,5 @@
import { Field, ObjectType } from 'type-graphql'; import { Field, ObjectType } from 'type-graphql';
import GitHubUser from './github-user';
@ObjectType() @ObjectType()
export default class PromptInfoApplication { export default class PromptInfoApplication {
@ -15,4 +16,12 @@ export default class PromptInfoApplication {
@Field(() => Boolean) @Field(() => Boolean)
public verified!: boolean; public verified!: boolean;
@Field(() => GitHubUser)
public owner!: GitHubUser;
@Field(() => String, {
nullable: true,
})
public homepage!: string | null;
} }

View file

@ -4,6 +4,7 @@ import {
Arg, Ctx, FieldResolver, Query, Resolver, Root, Arg, Ctx, FieldResolver, Query, Resolver, Root,
} from 'type-graphql'; } from 'type-graphql';
import database from '../../../database/database'; import database from '../../../database/database';
import { getUser } from '../../../graphql/github/sdk';
import { UnknownPromptError } from '../errors'; import { UnknownPromptError } from '../errors';
import PromptInfo from '../models/prompt-info'; import PromptInfo from '../models/prompt-info';
import type PromptInfoApplication from '../models/prompt-info-application'; import type PromptInfoApplication from '../models/prompt-info-application';
@ -39,6 +40,8 @@ export default class PromptInfoResolver implements ResolverInterface<PromptInfo>
iconUrl: application.iconUrl, iconUrl: application.iconUrl,
iconColor: application.iconColor, iconColor: application.iconColor,
verified: application.verified, verified: application.verified,
homepage: application.homepage,
owner: await getUser(application.ownerGitHubLogin),
}; };
} }
} }

View file

@ -0,0 +1,122 @@
<template>
<v-dialog v-model="value" max-width="450">
<template #activator="{ on: dialogOn }">
<v-tooltip bottom>
<template #activator="{ on: tooltipOn }">
<v-card
class="d-inline-block px-1"
color="primary--text"
rounded
flat
v-on="{ ...dialogOn, ...tooltipOn }"
link
>
{{ promptInfo.application.name }}
</v-card>
</template>
Kliknij aby zobaczyć informacje o aplikacji
</v-tooltip>
</template>
<v-card>
<v-card-title>
Informacje o aplikacji
</v-card-title>
<v-list>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-information</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-subtitle class="text-overline">
Nazwa aplikacji
</v-list-item-subtitle>
<v-list-item-title>
{{ promptInfo.application.name }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item
v-if="promptInfo.application.homepage"
:href="promptInfo.application.homepage"
target="_blank"
rel="noopener"
>
<v-list-item-icon>
<v-icon>mdi-home</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-subtitle class="text-overline">
Strona domowa
</v-list-item-subtitle>
<v-list-item-title>
{{ promptInfo.application.homepage }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-list-item
:href="promptInfo.application.owner.url"
target="_blank"
rel="noopener"
>
<v-list-item-icon>
<v-icon>mdi-github</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-subtitle class="text-overline">
Twórca
</v-list-item-subtitle>
<v-list-item-title v-if="promptInfo.application.owner.name">
{{ promptInfo.application.owner.name }}
<span class="text--secondary">
({{ promptInfo.application.owner.login }})
</span>
</v-list-item-title>
<v-list-item-title v-else>
{{ promptInfo.application.owner.login }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
<v-alert
color="green"
icon="mdi-check"
text
class="mx-2"
v-if="promptInfo.application.verified"
>
Aplikacja zweryfikowana
</v-alert>
<v-alert
color="grey darken-2"
icon="mdi-close"
text
class="mx-2"
v-else
>
Aplikacja nie została zweryfikowana
</v-alert>
<v-card-actions>
<v-spacer />
<v-btn color="primary" text @click="value = false">Zamknij</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { PromptInfo } from '@/types';
@Component({
name: 'AppInfoDialog',
})
export default class AppInfoDialog extends Vue {
@Prop({
required: true,
type: Object,
})
promptInfo!: PromptInfo;
value = false;
}
</script>

View file

@ -3,7 +3,7 @@
<div class="pt-16"> <div class="pt-16">
<h2 class="text-subtitle-1 text--secondary mt-6 mb-2 px-4"> <h2 class="text-subtitle-1 text--secondary mt-6 mb-2 px-4">
Aplikacja Aplikacja
<span class="text--primary">{{ promptInfo.application.name }}</span> <app-info-dialog :prompt-info="promptInfo" />
chce uzyskać dostęp do twojego konta VULCAN UONET+ przez Wulkanowy Bridge chce uzyskać dostęp do twojego konta VULCAN UONET+ przez Wulkanowy Bridge
</h2> </h2>
<v-subheader>Uprawnienia aplikacji</v-subheader> <v-subheader>Uprawnienia aplikacji</v-subheader>
@ -46,9 +46,11 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'; import { Component, Prop, Vue } from 'vue-property-decorator';
import { PromptInfo } from '@/types'; import { PromptInfo } from '@/types';
import AppInfoDialog from '@/compontents/authenticate-prompt-windows/app-info-dialog.vue';
@Component({ @Component({
name: 'OverviewWindow', name: 'OverviewWindow',
components: { AppInfoDialog },
}) })
export default class OverviewWindow extends Vue { export default class OverviewWindow extends Vue {
@Prop({ @Prop({

View file

@ -31,5 +31,9 @@ export default class DialogApp extends Vue {
.v-card__text, .v-card__title { .v-card__text, .v-card__title {
word-break: normal; word-break: normal;
} }
.no-basis {
flex-basis: 0;
}
} }
</style> </style>

View file

@ -45,6 +45,15 @@ export type PromptInfoApplication = {
iconUrl: Maybe<Scalars['String']>; iconUrl: Maybe<Scalars['String']>;
iconColor: Scalars['String']; iconColor: Scalars['String'];
verified: Scalars['Boolean']; verified: Scalars['Boolean'];
owner: GitHubUser;
homepage: Maybe<Scalars['String']>;
};
export type GitHubUser = {
__typename?: 'GitHubUser';
login: Scalars['String'];
name: Maybe<Scalars['String']>;
url: Scalars['String'];
}; };
export type Mutation = { export type Mutation = {
@ -101,7 +110,11 @@ export type GetPromptInfoQuery = (
& Pick<PromptInfo, 'id' | 'scopes' | 'studentsMode'> & Pick<PromptInfo, 'id' | 'scopes' | 'studentsMode'>
& { application: ( & { application: (
{ __typename?: 'PromptInfoApplication' } { __typename?: 'PromptInfoApplication' }
& Pick<PromptInfoApplication, 'name' | 'iconUrl' | 'iconColor' | 'verified'> & Pick<PromptInfoApplication, 'name' | 'iconUrl' | 'iconColor' | 'verified' | 'homepage'>
& { owner: (
{ __typename?: 'GitHubUser' }
& Pick<GitHubUser, 'login' | 'name' | 'url'>
); }
); } ); }
); } ); }
); );
@ -133,6 +146,12 @@ export const GetPromptInfoDocument = gql`
iconUrl iconUrl
iconColor iconColor
verified verified
homepage
owner {
login
name
url
}
} }
} }
} }

View file

@ -10,6 +10,12 @@ export default gql`query GetPromptInfo($promptId: String!) {
iconUrl iconUrl
iconColor iconColor
verified verified
homepage
owner {
login
name
url
}
} }
} }
} }

View file

@ -92,7 +92,7 @@
<style lang="scss"> <style lang="scss">
.authenticate-prompt-app { .authenticate-prompt-app {
.avatar-sheet { .avatar-sheet {
border-radius: 50%; border-radius: 50% !important;
} }
.fill-height { .fill-height {

View file

@ -13,6 +13,12 @@ export interface PromptInfo {
iconUrl: string | null; iconUrl: string | null;
iconColor: string; iconColor: string;
verified: boolean; verified: boolean;
homepage: string | null;
owner: {
login: string;
name: string | null;
url: string;
};
}; };
} }