├── .browserslistrc
├── cypress.json
├── babel.config.js
├── src
├── shims-vue.d.ts
├── utils
│ ├── validate
│ │ ├── index.ts
│ │ ├── validators.ts
│ │ └── createValidateSchema.ts
│ ├── formatDate
│ │ └── formatDate.ts
│ ├── debounce
│ │ └── debounce.ts
│ ├── yandexUrl
│ │ └── getYandexUrl.ts
│ └── persist
│ │ └── persist.ts
├── types
│ ├── routes.ts
│ ├── events.ts
│ └── chats.ts
├── shims-vuetify.d.ts
├── assets
│ └── images
│ │ └── default-avatar.jpg
├── plugins
│ └── vuetify.ts
├── store
│ ├── store.ts
│ ├── index.ts
│ └── modules
│ │ ├── auth
│ │ └── auth.ts
│ │ └── chats
│ │ └── chats.ts
├── constants
│ └── index.ts
├── shims-tsx.d.ts
├── App.vue
├── main.ts
├── api
│ ├── base
│ │ ├── generate.js
│ │ └── swagger.yaml
│ ├── chats-service.ts
│ ├── user-service.ts
│ ├── response-handler.ts
│ └── generated
│ │ └── generated-service.ts
├── components
│ ├── chats.vue
│ ├── chat.vue
│ └── virtual-scroll.vue
├── router
│ └── index.ts
└── views
│ ├── chats-view.vue
│ ├── chat-create-view.vue
│ ├── signin-view.vue
│ └── signup-view.vue
├── jest.config.js
├── public
├── favicon.ico
└── index.html
├── .editorconfig
├── .gitignore
├── vue.config.js
├── .eslintrc.js
├── tsconfig.json
├── README.md
└── package.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "pluginsFile": "tests/e2e/plugins/index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/cli-plugin-babel/preset"],
3 | };
4 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.vue" {
2 | import Vue from "vue";
3 |
4 | export default Vue;
5 | }
6 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
3 | };
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alvar91/ozon-tech-hw6-vue-vuex-tsx-vuetify/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/utils/validate/index.ts:
--------------------------------------------------------------------------------
1 | export { schema } from "./createValidateSchema";
2 | export { validators } from "./validators";
3 |
--------------------------------------------------------------------------------
/src/types/routes.ts:
--------------------------------------------------------------------------------
1 | export interface Route {
2 | title: string;
3 | to: string;
4 | }
5 |
6 | export type Routes = Route[];
7 |
--------------------------------------------------------------------------------
/src/shims-vuetify.d.ts:
--------------------------------------------------------------------------------
1 | declare module "vuetify/lib/framework" {
2 | import Vuetify from "vuetify";
3 | export default Vuetify;
4 | }
5 |
--------------------------------------------------------------------------------
/src/assets/images/default-avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alvar91/ozon-tech-hw6-vue-vuex-tsx-vuetify/HEAD/src/assets/images/default-avatar.jpg
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/src/plugins/vuetify.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuetify from 'vuetify/lib/framework';
3 |
4 | Vue.use(Vuetify);
5 |
6 | export default new Vuetify();
7 |
--------------------------------------------------------------------------------
/src/types/events.ts:
--------------------------------------------------------------------------------
1 | export interface HandleInputChange extends Event {
2 | target: HTMLInputElement;
3 | }
4 |
5 | export interface HandleChange extends Event {
6 | target: HTMLElement;
7 | }
8 |
--------------------------------------------------------------------------------
/src/store/store.ts:
--------------------------------------------------------------------------------
1 | import { Module } from "vuex-simple";
2 | import { AuthModule } from "./modules/auth/auth";
3 | import { ChatsModule } from "./modules/chats/chats";
4 |
5 | export class Store {
6 | @Module()
7 | public auth = new AuthModule();
8 |
9 | @Module()
10 | public chats = new ChatsModule();
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | export enum ROUTES_TO {
2 | // signin = "/auth/signin",
3 | signin = "/",
4 | signup = "/auth/signup",
5 | logout = "/auth/logout",
6 | chats = "/chats",
7 | createChat = "/chats/create",
8 | }
9 |
10 | export const FIRST_PAGE = 1;
11 |
12 | export const PERSISTED_STORAGE_NAME = "OZON_CHATS_JOURNEY_MAP";
13 |
--------------------------------------------------------------------------------
/src/utils/formatDate/formatDate.ts:
--------------------------------------------------------------------------------
1 | function padTo2Digits(num: number): string {
2 | return num.toString().padStart(2, "0");
3 | }
4 |
5 | export function formatDate(date: Date): string {
6 | return [
7 | padTo2Digits(date.getDate()),
8 | padTo2Digits(date.getMonth() + 1),
9 | date.getFullYear(),
10 | ].join(".");
11 | }
12 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Vuex from "vuex";
3 | import { createVuexStore } from "vuex-simple";
4 |
5 | import { Store } from './store';
6 |
7 | Vue.use(Vuex);
8 |
9 | const store = createVuexStore(new Store(), {
10 | strict: false,
11 | modules: {},
12 | plugins: [],
13 | });
14 |
15 | export default store;
16 |
--------------------------------------------------------------------------------
/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from "vue";
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
19 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const { defineConfig } = require("@vue/cli-service");
2 | module.exports = defineConfig({
3 | transpileDependencies: ["vuetify"],
4 | devServer: {
5 | proxy: {
6 | "^/api/v2": {
7 | target: "http://62.113.98.233:5000",
8 | secure: false,
9 | changeOrigin: true,
10 | ws: true,
11 | },
12 | },
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "@/App.vue";
3 | import vuetify from "@/plugins/vuetify";
4 |
5 | import router from "@/router";
6 | import store from "@/store";
7 |
8 | import Notifications from "vue-notification";
9 |
10 | Vue.config.productionTip = false;
11 | Vue.use(Notifications);
12 |
13 | new Vue({
14 | vuetify,
15 | store,
16 | router,
17 | render: (h) => h(App),
18 | }).$mount("#app");
19 |
--------------------------------------------------------------------------------
/src/types/chats.ts:
--------------------------------------------------------------------------------
1 | export interface LastMessage {
2 | user: {
3 | first_name: string;
4 | second_name: string;
5 | avatar: string;
6 | email: string;
7 | login: string;
8 | phone: string;
9 | };
10 | time: string;
11 | content: string;
12 | }
13 | export interface Chat {
14 | id: number;
15 | title: string;
16 | avatar: string;
17 | unread_count: number;
18 | last_message: LastMessage;
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/debounce/debounce.ts:
--------------------------------------------------------------------------------
1 | export function Debounce(timeout: number) {
2 | let timeoutRef;
3 |
4 | return function (
5 | target,
6 | propertyKey: string,
7 | descriptor: PropertyDescriptor
8 | ) {
9 | const original = descriptor.value;
10 |
11 | descriptor.value = function (...args) {
12 | clearTimeout(timeoutRef);
13 |
14 | timeoutRef = setTimeout(() => {
15 | original.apply(this, args);
16 | }, timeout);
17 | };
18 |
19 | return descriptor;
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/yandexUrl/getYandexUrl.ts:
--------------------------------------------------------------------------------
1 | const VUE_APP_YANDEX_OAUTH2_CLIENT_ID = "c98baded858640108b2a74710f9b9a20";
2 | export const VUE_APP_YANDEX_OAUTH2_REDIRECT = "http://localhost:5000/";
3 |
4 | export const getYandexUrl = (from) => {
5 | const rootUrl = `https://oauth.yandex.ru/authorize?`;
6 |
7 | const options: any = {
8 | redirect_uri: VUE_APP_YANDEX_OAUTH2_REDIRECT,
9 | client_id: VUE_APP_YANDEX_OAUTH2_CLIENT_ID,
10 | response_type: "code",
11 | force_confirm: true,
12 | state: from,
13 | };
14 |
15 | const qs = new URLSearchParams(options);
16 |
17 | return `${rootUrl}${qs.toString()}`;
18 | };
19 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: ["@vue/typescript", "plugin:vue/essential", "eslint:recommended"],
7 | parserOptions: {
8 | ecmaFeatures: {
9 | legacyDecorators: true,
10 | },
11 | },
12 | rules: {
13 | "vue/multi-word-component-names": 0,
14 | "no-unused-vars": "off",
15 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
16 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
17 | },
18 | overrides: [
19 | {
20 | files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"],
21 | env: {
22 | jest: true,
23 | },
24 | },
25 | ],
26 | };
27 |
--------------------------------------------------------------------------------
/src/utils/persist/persist.ts:
--------------------------------------------------------------------------------
1 | import { PERSISTED_STORAGE_NAME } from "@/constants";
2 |
3 | export class PersistStorage {
4 | static initiateStorage() {
5 | localStorage.setItem(PERSISTED_STORAGE_NAME, JSON.stringify({}));
6 | }
7 |
8 | static getStorage() {
9 | let storage = localStorage.getItem(PERSISTED_STORAGE_NAME);
10 |
11 | if (!storage) {
12 | this.initiateStorage();
13 | storage = localStorage.getItem(PERSISTED_STORAGE_NAME);
14 | }
15 |
16 | return JSON.parse(storage as string);
17 | }
18 |
19 | static setStorage(path) {
20 | const storage = this.getStorage();
21 |
22 | if (!storage[path]) storage[path] = [];
23 |
24 | storage[path].push({ path, date: new Date() });
25 |
26 | localStorage.setItem(PERSISTED_STORAGE_NAME, JSON.stringify(storage));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/base/generate.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { generateApi } = require("swagger-typescript-api");
3 |
4 | /* NOTE: all fields are optional expect one of `output`, `url`, `spec` */
5 | generateApi({
6 | // имя генерируемого файла
7 | name: "generated-service.ts",
8 | // путь, куда будет сохранен генерируемый файл
9 | output: path.resolve(process.cwd(), "../generated"),
10 | // источник
11 | // url (для ссылки на swagger.json в сети) или input (для файла swagger.json или swagger.yaml в проекте)
12 | // url: 'http://localhost:8080/swagger.json',
13 | input: path.resolve(process.cwd(), "./swagger.yaml"),
14 | // http клиент: fetch или axios
15 | httpClientType: "axios",
16 | generateResponses: true,
17 | generateClient: true,
18 | enumNamesAsValues: false,
19 | });
20 |
21 | // для запуска, выполнить "node generate.js" в терминали в папке с этим файлом
22 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/api/chats-service.ts:
--------------------------------------------------------------------------------
1 | import { Api, CreateChatRequest } from "./generated/generated-service";
2 |
3 | import { WithErrorNotification } from "./response-handler";
4 |
5 | const getOptions = ({ pageNumber = 1, title = "", step = 10 }) => {
6 | return {
7 | offset: step * pageNumber,
8 | limit: step,
9 | title,
10 | };
11 | };
12 |
13 | export class ChatsService {
14 | static chatsService = new Api().chats;
15 |
16 | @WithErrorNotification({
17 | errorMessage: "Не удалось получить список чатов!",
18 | })
19 | static async fetchChats(pageNumber: number, title: string, step?: number) {
20 | return await this.chatsService.chatsList(getOptions({ pageNumber, title, step }));
21 | }
22 |
23 | @WithErrorNotification({
24 | errorMessage: "Не удалось создать чат!",
25 | })
26 | static async createChat(data: CreateChatRequest) {
27 | return await this.chatsService.chatsCreate(data);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/validate/validators.ts:
--------------------------------------------------------------------------------
1 | import {
2 | required,
3 | requiredIf,
4 | alpha,
5 | email,
6 | numeric,
7 | helpers,
8 | } from "vuelidate/lib/validators";
9 |
10 | export const validators = {
11 | required,
12 | requiredIf,
13 | alpha,
14 | alphaRus: helpers.regex("alphaRus", /^[а-яё]*$/i),
15 | numeric,
16 | email,
17 | phoneLength: (value) => value.length === 17,
18 | };
19 |
20 | const errorMessages = {
21 | required: "Обязательное поле",
22 | alpha: "Только латинские буквы",
23 | alphaRus: "Только русские буквы",
24 | numeric: "Только цифры",
25 | email: "Неправильный формат электронной почты",
26 | phoneLength: "Заполните номер телефона",
27 | };
28 |
29 | export const getErrorMessages = (errors) => {
30 | return Object.entries(errors).reduce((acc: any, [key, value]) => {
31 | if (value) {
32 | const message =
33 | (errorMessages[key] as string) || "Неправильно заполнено поле";
34 | acc.push(message);
35 | }
36 | return acc;
37 | }, []);
38 | };
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "noImplicitAny": false,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "useDefineForClassFields": true,
15 | "sourceMap": true,
16 | "resolveJsonModule": true,
17 | "baseUrl": ".",
18 | "types": [
19 | "webpack-env",
20 | "jest",
21 | "vuetify"
22 | ],
23 | "paths": {
24 | "@/*": [
25 | "src/*"
26 | ]
27 | },
28 | "lib": [
29 | "esnext",
30 | "dom",
31 | "dom.iterable",
32 | "scripthost"
33 | ]
34 | },
35 | "include": [
36 | "src/**/*.ts",
37 | "src/**/*.tsx",
38 | "src/**/*.vue",
39 | "tests/**/*.ts",
40 | "tests/**/*.tsx"
41 | , "src/router/index.ts", "src/main.ts" ],
42 | "exclude": [
43 | "node_modules"
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/src/api/user-service.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Api,
3 | SignUpRequest,
4 | SignInRequest,
5 | OauthSignInRequest,
6 | } from "./generated/generated-service";
7 |
8 | import { WithErrorNotification } from "./response-handler";
9 | export class UserService {
10 | static userService = new Api().auth;
11 | static userOauthService = new Api().oauth;
12 |
13 | @WithErrorNotification({
14 | errorMessage: "Не удалось создать пользователя!",
15 | })
16 | static async createUser(data: SignUpRequest) {
17 | return await this.userService.signupCreate(data);
18 | }
19 |
20 | @WithErrorNotification({
21 | errorMessage: "Не удалось войти!",
22 | })
23 | static async logIn(data: SignInRequest) {
24 | return await this.userService.signinCreate(data);
25 | }
26 |
27 | @WithErrorNotification({
28 | errorMessage: "Не удалось выйти!",
29 | })
30 | static async logOut() {
31 | return await this.userService.logoutCreate();
32 | }
33 |
34 | @WithErrorNotification({
35 | errorMessage: "Не удалось войти!",
36 | })
37 | static async logInYandex(data: OauthSignInRequest) {
38 | return await this.userOauthService.yandexCreate(data);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/store/modules/auth/auth.ts:
--------------------------------------------------------------------------------
1 | import { Action } from "vuex-simple";
2 |
3 | import { UserService } from "@/api/user-service";
4 |
5 | import router from "@/router";
6 | import { ROUTES_TO, FIRST_PAGE } from "@/constants/index";
7 |
8 | export class AuthModule {
9 | @Action()
10 | async createUser(data) {
11 | const createUserResponse = await UserService.createUser(data);
12 | if (createUserResponse?.status === 200) {
13 | localStorage.isAuthenticated = true;
14 | router.push(`${ROUTES_TO.chats}`);
15 | }
16 | }
17 |
18 | @Action()
19 | async logIn(data) {
20 | const loginResponse = await UserService.logIn(data);
21 | if (loginResponse?.status === 200) {
22 | localStorage.isAuthenticated = true;
23 | router.push(`${ROUTES_TO.chats}`);
24 | }
25 | }
26 |
27 | @Action()
28 | async logOut() {
29 | const response = await UserService.logOut();
30 |
31 | if (response?.status === 200) {
32 | localStorage.removeItem("isAuthenticated");
33 | router.push({ name: "SigninView" });
34 | }
35 | }
36 |
37 | @Action()
38 | async logInYandex(data) {
39 | const response = await UserService.logInYandex(data);
40 |
41 | if (response?.status === 200) {
42 | localStorage.isAuthenticated = true;
43 | router.push(`${ROUTES_TO.chats}`);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/utils/validate/createValidateSchema.ts:
--------------------------------------------------------------------------------
1 | import { getErrorMessages } from "./validators";
2 |
3 | const isFieldDirty = (field) => field?.$dirty;
4 |
5 | const validate = (field, errors) => {
6 | return isFieldDirty(field) ? getErrorMessages(errors) : [];
7 | };
8 |
9 | const validateLogin = (field) =>
10 | validate(field, {
11 | required: !field.required,
12 | });
13 |
14 | const validatePassword = (field) =>
15 | validate(field, {
16 | required: !field.required,
17 | });
18 |
19 | const validateFirstName = (field) =>
20 | validate(field, {
21 | required: !field.required,
22 | alphaRus: !field.alphaRus,
23 | });
24 |
25 | const validateSecondName = (field) =>
26 | validate(field, {
27 | required: !field.required,
28 | alphaRus: !field.alphaRus,
29 | });
30 |
31 | const validateEmail = (field) =>
32 | validate(field, {
33 | required: !field.required,
34 | email: !field.email,
35 | });
36 |
37 | const validatePhone = (field) =>
38 | validate(field, {
39 | required: !field.required,
40 | phoneLength: !field.phoneLength,
41 | });
42 |
43 | const validateChatTitle = (field) =>
44 | validate(field, {
45 | required: !field.required,
46 | });
47 |
48 | export const schema = {
49 | validateLogin,
50 | validatePassword,
51 | validateFirstName,
52 | validateSecondName,
53 | validateEmail,
54 | validatePhone,
55 | validateChatTitle,
56 | };
57 |
--------------------------------------------------------------------------------
/src/components/chats.vue:
--------------------------------------------------------------------------------
1 |
57 |
--------------------------------------------------------------------------------
/src/api/response-handler.ts:
--------------------------------------------------------------------------------
1 | import { AxiosError } from "axios";
2 | import router from "@/router";
3 |
4 | interface Options {
5 | errorMessage?: string;
6 | defaultValue?: R | undefined;
7 | }
8 |
9 | const showErrorNotification = (error: Error, message?: string) => {
10 | const text = message || error.message || "Что-то пошло не так!";
11 |
12 | alert(text);
13 | };
14 |
15 | const HandleErrorDecorator = (
16 | handler: (error: AxiosError, message?: string) => void,
17 | defaultValue?: R | undefined,
18 | message?: string
19 | ) => {
20 | return (target: unknown, key: string, descriptor: PropertyDescriptor) => {
21 | const original = descriptor.value;
22 |
23 | descriptor.value = async function (...args: unknown[]) {
24 | try {
25 | return await original.apply(this, args);
26 | } catch (error) {
27 | handler(error as AxiosError, message);
28 | return defaultValue;
29 | }
30 | };
31 |
32 | return descriptor;
33 | };
34 | };
35 |
36 | export const WithErrorNotification = ({
37 | errorMessage,
38 | defaultValue,
39 | }: Options) => {
40 | return HandleErrorDecorator(
41 | (error, message?: string) => {
42 | if (error?.response?.status === 401) {
43 | localStorage.removeItem("isAuthenticated");
44 | router.push({ name: "SigninView" });
45 | }
46 |
47 | showErrorNotification(error, message);
48 | },
49 | defaultValue,
50 | errorMessage
51 | );
52 | };
53 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter, { RouteConfig } from "vue-router";
3 |
4 | import SigninView from "@/views/signin-view.vue";
5 |
6 | import { ROUTES_TO } from "@/constants";
7 |
8 | import { PersistStorage } from "@/utils/persist/persist";
9 |
10 | Vue.use(VueRouter);
11 |
12 | const routes: Array = [
13 | {
14 | path: ROUTES_TO.signin,
15 | name: "SigninView",
16 | component: SigninView,
17 | },
18 | {
19 | path: ROUTES_TO.signup,
20 | name: "SignupView",
21 | component: () => import("@/views/signup-view.vue"),
22 | },
23 | {
24 | path: `${ROUTES_TO.chats}`,
25 | name: "ChatsView",
26 | component: () => import("@/views/chats-view.vue"),
27 | meta: {
28 | requiresAuth: true,
29 | },
30 | },
31 | {
32 | path: ROUTES_TO.createChat,
33 | name: "ChatCreateView",
34 | component: () => import("@/views/chat-create-view.vue"),
35 | meta: {
36 | requiresAuth: true,
37 | },
38 | },
39 | {
40 | path: "*",
41 | redirect: ROUTES_TO.signin,
42 | },
43 | ];
44 |
45 | const router = new VueRouter({
46 | mode: "history",
47 | routes,
48 | });
49 |
50 | router.beforeEach((to, from, next) => {
51 | PersistStorage.setStorage(to.path);
52 |
53 | if (to.meta?.requiresAuth) {
54 | if (!localStorage.getItem("isAuthenticated")) {
55 | router.push({ name: "SigninView" });
56 | } else {
57 | next();
58 | }
59 | } else {
60 | if (localStorage.getItem("isAuthenticated")) {
61 | router.push(`${ROUTES_TO.chats}`);
62 | } else {
63 | next();
64 | }
65 | }
66 | });
67 |
68 | export default router;
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Домашка 6 #
2 |
3 | ## Задание ##
4 | За исходники взять д/з №5
5 | Переписать компоненты с .vue на .tsx
6 | Заменить в таблице пагинацию (из д/з №5) на virtual scroll (взять с воркшопа или реализовать свой)
7 | Реализовать ленивую загрузку для virtual scroll: после отрисовки последнего элемента отправлялся запрос на сервер, для получения следующих элементов списка. Если элементов больше нет, вывести предупреждение, что на данный момент все данные получены.
8 | Доп. задание:
9 | Реализовать фильтрацию в таблице (запрос "/chats", параметр "title")
10 | Добавить Guards:
11 | 1 - для проверки авторизации: сейчас для проверки авторизации используется запрос, необходимо написать Guards, который перед переходом на страницу будет проверять авторизацию с помощью этого запроса
12 | 2 - для логирования посещенных страниц: добавить Guards, который сохраняет в массив список посещенных страниц. Такое может понадобиться для сбора метрик по посещению страниц сайта. Хранить можно в (local/session/cache)Storage
13 | Сгенерировать API и перейти на его использование с декораторами (пример в материалах воркшопа, в директории "api")
14 | Доп. материалы:
15 | для генерации API использовать - https://github.com/acacode/swagger-typescript-api
16 | config для генератора API (конфиурация и инструкция в материалах воркшопа)
17 |
18 | ## Project setup
19 | ```
20 | yarn install
21 | ```
22 |
23 | ### Compiles and hot-reloads for development
24 | ```
25 | yarn serve
26 | ```
27 |
28 | ### Compiles and minifies for production
29 | ```
30 | yarn build
31 | ```
32 |
33 | ### Lints and fixes files
34 | ```
35 | yarn lint
36 | ```
37 |
38 | ### Customize configuration
39 | See [Configuration Reference](https://cli.vuejs.org/config/).
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "homework-6",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve --port 5000",
7 | "build": "vue-cli-service build",
8 | "test:unit": "vue-cli-service test:unit",
9 | "test:e2e": "vue-cli-service test:e2e",
10 | "lint": "vue-cli-service lint"
11 | },
12 | "dependencies": {
13 | "@types/vuelidate": "^0.7.15",
14 | "axios": "^1.1.3",
15 | "core-js": "^3.8.3",
16 | "v-mask": "^2.3.0",
17 | "vue": "^2.6.14",
18 | "vue-class-component": "^7.2.3",
19 | "vue-notification": "^1.3.20",
20 | "vue-property-decorator": "^9.1.2",
21 | "vue-router": "^3.5.3",
22 | "vuelidate": "^0.7.6",
23 | "vuetify": "^2.6.0",
24 | "vuex": "^3.6.2",
25 | "vuex-simple": "^2.2.0"
26 | },
27 | "devDependencies": {
28 | "@types/jest": "^27.5.2",
29 | "@typescript-eslint/eslint-plugin": "^5.4.0",
30 | "@typescript-eslint/parser": "^5.4.0",
31 | "@vue/cli-plugin-babel": "~5.0.0",
32 | "@vue/cli-plugin-e2e-cypress": "~5.0.0",
33 | "@vue/cli-plugin-eslint": "~5.0.0",
34 | "@vue/cli-plugin-router": "~5.0.0",
35 | "@vue/cli-plugin-typescript": "~5.0.0",
36 | "@vue/cli-plugin-unit-jest": "~5.0.0",
37 | "@vue/cli-plugin-vuex": "~5.0.0",
38 | "@vue/cli-service": "~5.0.0",
39 | "@vue/eslint-config-airbnb": "^6.0.0",
40 | "@vue/eslint-config-prettier": "^7.0.0",
41 | "@vue/eslint-config-standard": "^6.1.0",
42 | "@vue/eslint-config-typescript": "^9.1.0",
43 | "@vue/test-utils": "^1.1.3",
44 | "@vue/vue2-jest": "^27.0.0-alpha.2",
45 | "babel-eslint": "^10.1.0",
46 | "babel-jest": "^27.0.6",
47 | "cypress": "^9.7.0",
48 | "eslint": "^7.32.0",
49 | "eslint-plugin-import": "^2.25.3",
50 | "eslint-plugin-node": "^11.1.0",
51 | "eslint-plugin-promise": "^5.1.0",
52 | "eslint-plugin-vue": "^8.0.3",
53 | "jest": "^27.0.5",
54 | "sass": "~1.32.0",
55 | "sass-loader": "^10.0.0",
56 | "ts-jest": "^27.0.4",
57 | "swagger-typescript-api": "^11.1.1",
58 | "typescript": "~4.5.5",
59 | "vue-cli-plugin-vuetify": "~2.5.8",
60 | "vue-template-compiler": "^2.7.13",
61 | "vuetify-loader": "^1.9.2"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/store/modules/chats/chats.ts:
--------------------------------------------------------------------------------
1 | import { Mutation, State, Action } from "vuex-simple";
2 |
3 | import { ChatsService } from "@/api/chats-service";
4 |
5 | import router from "@/router";
6 |
7 | import { ROUTES_TO, FIRST_PAGE } from "@/constants/index";
8 | export class ChatsModule {
9 | @State()
10 | chats = [];
11 |
12 | @State()
13 | currentPage = FIRST_PAGE;
14 |
15 | @State()
16 | totalPages = Infinity;
17 |
18 | @State()
19 | filterTitle = "";
20 |
21 | @Action()
22 | async createChatAction(data) {
23 | const createChatsResponse = await ChatsService.createChat(data);
24 |
25 | if (createChatsResponse?.status === 200) {
26 | router.push(`${ROUTES_TO.chats}`);
27 | }
28 | }
29 |
30 | @Mutation()
31 | setCurrentPage(newPage) {
32 | this.currentPage = newPage;
33 | }
34 |
35 | @Mutation()
36 | setTotalPages(newTotalPages) {
37 | this.totalPages = newTotalPages;
38 | }
39 |
40 | @Mutation()
41 | setFilterTitle(newTitle) {
42 | this.filterTitle = newTitle;
43 | }
44 |
45 | @Mutation()
46 | fetchChats(chats) {
47 | this.chats = chats;
48 | }
49 |
50 | @Mutation()
51 | appendFetchChats(chats) {
52 | this.chats = this.chats.concat(chats);
53 | }
54 |
55 | @Mutation()
56 | resetChatsStore() {
57 | this.chats = [];
58 | this.filterTitle = "";
59 | this.currentPage = FIRST_PAGE;
60 | }
61 |
62 | @Action()
63 | async fetchChatsAction() {
64 | const pageNumber = FIRST_PAGE;
65 | const title = this.filterTitle;
66 | const createChatsResponse = await ChatsService.fetchChats(
67 | pageNumber - 1,
68 | title
69 | );
70 |
71 | if (createChatsResponse?.status === 200) {
72 | this.fetchChats(createChatsResponse.data);
73 | this.setCurrentPage(pageNumber);
74 | }
75 | }
76 |
77 | @Action()
78 | async nextFetchChatsAction() {
79 | const pageNumber = this.currentPage + 1;
80 | const title = this.filterTitle;
81 |
82 | const createChatsResponse = await ChatsService.fetchChats(
83 | pageNumber - 1,
84 | title,
85 | );
86 |
87 | if (createChatsResponse?.status === 200) {
88 | const data = createChatsResponse.data;
89 | if (data.length === 0) {
90 | this.setTotalPages(pageNumber);
91 | }
92 |
93 | this.appendFetchChats(data);
94 | this.setCurrentPage(pageNumber);
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/views/chats-view.vue:
--------------------------------------------------------------------------------
1 |
93 |
--------------------------------------------------------------------------------
/src/components/chat.vue:
--------------------------------------------------------------------------------
1 |
92 |
--------------------------------------------------------------------------------
/src/views/chat-create-view.vue:
--------------------------------------------------------------------------------
1 |
108 |
--------------------------------------------------------------------------------
/src/components/virtual-scroll.vue:
--------------------------------------------------------------------------------
1 |
139 |
--------------------------------------------------------------------------------
/src/views/signin-view.vue:
--------------------------------------------------------------------------------
1 |
151 |
--------------------------------------------------------------------------------
/src/views/signup-view.vue:
--------------------------------------------------------------------------------
1 |
206 |
--------------------------------------------------------------------------------
/src/api/generated/generated-service.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* tslint:disable */
3 | /*
4 | * ---------------------------------------------------------------
5 | * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
6 | * ## ##
7 | * ## AUTHOR: acacode ##
8 | * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
9 | * ---------------------------------------------------------------
10 | */
11 |
12 | /** @example {"id":123,"first_name":"Petya","second_name":"Pupkin","display_name":"Petya Pupkin","login":"userLogin","email":"my@email.com","phone":"89223332211","avatar":"/path/to/avatar.jpg"} */
13 | export interface UserResponse {
14 | /** User id */
15 | id: number;
16 | /** First name */
17 | first_name: string;
18 | /** Second name */
19 | second_name: string;
20 | /** Display name */
21 | display_name: string;
22 | /** User login - unique */
23 | login: string;
24 | /** Email */
25 | email: string;
26 | /** Phone */
27 | phone: string;
28 | /** Avatar */
29 | avatar: string;
30 | }
31 |
32 | export interface SignUpRequest {
33 | /** First name */
34 | first_name: string;
35 | /** Second name */
36 | second_name: string;
37 | /** User login - unique */
38 | login: string;
39 | /** Email /^\S+@\S+$/ */
40 | email: string;
41 | /** Password */
42 | password: string;
43 | /** Phone /^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$/ */
44 | phone: string;
45 | }
46 |
47 | export interface SignInRequest {
48 | /** User login */
49 | login: string;
50 | /** Password */
51 | password: string;
52 | }
53 |
54 | export interface SignUpResponse {
55 | /** Created User ID */
56 | id: number;
57 | }
58 |
59 | export interface CreateChatRequest {
60 | /** Chat title */
61 | title: string;
62 | }
63 |
64 | export interface UsersRequest {
65 | users: number[];
66 | /** Chat id */
67 | chatId: number;
68 | }
69 |
70 | /** @example {"id":123,"title":"my-chat","avatar":"/123/avatar1.jpg","unread_count":15,"last_message":{"user":{"first_name":"Petya","second_name":"Pupkin","avatar":"/path/to/avatar.jpg","email":"my@email.com","login":"userLogin","phone":"8(911)-222-33-22"},"time":"2022-11-02T16:55:02.599Z","content":"this is message content"}} */
71 | export interface ChatsResponse {
72 | /** Chat id */
73 | id: number;
74 | /** Chat title */
75 | title: string;
76 | /** Chat avatar */
77 | avatar: string;
78 | /** Number of unread messages in chat for current user */
79 | unread_count: number;
80 | last_message: {
81 | /**
82 | * Message user (sender)
83 | * @format date-time
84 | */
85 | user?: UserResponse;
86 | /**
87 | * Message timestamp
88 | * @format timestamp
89 | */
90 | time?: string;
91 | /** Message content */
92 | content?: string;
93 | };
94 | }
95 |
96 | export interface ChatDeleteRequest {
97 | /** Chat id */
98 | chatId: number;
99 | }
100 |
101 | /** @example {"userId":12,"result":{"id":123,"title":"deleted-chat","avatar":"/123/avatar1.jpg"}} */
102 | export interface ChatDeleteResponse {
103 | /** User id */
104 | userId: number;
105 | result: ChatsResponse;
106 | }
107 |
108 | export interface ChatArchiveRequest {
109 | /** Chat id */
110 | chatId: number;
111 | }
112 |
113 | export interface ChatArchiveResponse {
114 | /** User id */
115 | userId: number;
116 | result: ChatsResponse;
117 | }
118 |
119 | export interface ChatsMessagesTokenResponse {
120 | /** Token for web socket server */
121 | token: string;
122 | }
123 |
124 | /** @example {"unread_count":12} */
125 | export interface UnreadCountResponse {
126 | /** New messages count */
127 | unread_count: number;
128 | }
129 |
130 | export interface LeaderboardNewLeaderRequest {
131 | /** Leaderboard data object, any type */
132 | data: object;
133 | /** Which field is used to sort (if new value of the field more than old, data is stored) */
134 | ratingFieldName: string;
135 | /** Your team name. Used to make unique leaderboard for each project. */
136 | teamName?: string;
137 | }
138 |
139 | export interface LeaderboardRequest {
140 | /** Which field is used to sort */
141 | ratingFieldName: string;
142 | /** Used to paginate between pages. If limit is 10, then for the 1st page - cursor=0, for the 2nd page - cursor=10. */
143 | cursor: number;
144 | /** Maximum amount of leaders to return */
145 | limit: number;
146 | }
147 |
148 | export interface OauthSignInRequest {
149 | /** User code from Yandex */
150 | code: string;
151 | /** Redirect uri that you are using for oauth */
152 | redirect_uri: string;
153 | }
154 |
155 | export interface ServiceId {
156 | /** Service id */
157 | service_id: string;
158 | }
159 |
160 | export interface BadRequestError {
161 | /** Error message */
162 | reason: string;
163 | }
164 |
165 | export interface UserUpdateRequest {
166 | /** First name */
167 | first_name: string;
168 | /** Second name */
169 | second_name: string;
170 | /** Display Name */
171 | display_name: string;
172 | /** User login - unique */
173 | login: string;
174 | /** Email */
175 | email: string;
176 | /** Phone */
177 | phone: string;
178 | }
179 |
180 | export interface UserRequest {
181 | /** First name */
182 | first_name: string;
183 | /** Second name */
184 | second_name: string;
185 | /** Display Name */
186 | display_name: string;
187 | /** User login - unique */
188 | login: string;
189 | /** Email */
190 | email: string;
191 | /** Phone */
192 | phone: string;
193 | }
194 |
195 | export interface FindUserRequest {
196 | /** User login (beginning of login) */
197 | login: string;
198 | }
199 |
200 | export interface ChangePasswordRequest {
201 | /** Old password */
202 | oldPassword: string;
203 | /** New password */
204 | newPassword: string;
205 | }
206 |
207 | /** @example {"id":123,"user_id":231,"path":"/32543654dsf/434534r3rsddfs_my-file.jpg","filename":"my-file.jpg","content_type":"image/jpeg","content_size":543672,"upload_date":"2022-11-02T16:55:02.599Z"} */
208 | export interface Resource {
209 | /** Message id */
210 | id: number;
211 | /** User id */
212 | user_id: number;
213 | /** Server relative file path */
214 | path: string;
215 | /** Initial file name */
216 | filename: string;
217 | /** File content type (e.g "image/jpeg" for .jpg images) */
218 | content_type: string;
219 | /** File size in bytes */
220 | content_size: number;
221 | /**
222 | * Resource uploading time
223 | * @format date-time
224 | */
225 | upload_date: string;
226 | }
227 |
228 | /** @example {"id":123,"user_id":231,"chat_id":312,"time":"2022-11-02T16:55:02.599Z","type":"file","content":132,"file":{"id":132,"user_id":231,"path":"/32543654dsf/434534r3rsddfs_my-file.jpg","filename":"my-file.jpg","content_type":"image/jpeg","content_size":543672,"upload_date":"2022-11-02T16:55:02.599Z"}} */
229 | export interface ChatMessage {
230 | /** Message id */
231 | id: number;
232 | /** User id */
233 | user_id: number;
234 | /** Chat id */
235 | chat_id: number;
236 | /**
237 | * Message sent time
238 | * @format date-time
239 | */
240 | time: string;
241 | /** Message type */
242 | type: "message" | "file";
243 | /** Message content (message text for messages and resourceId for files) */
244 | content: string;
245 | /** File */
246 | file?: Resource;
247 | }
248 |
249 | /** @example {"id":123,"first_name":"petya","second_name":"petrov","display_name":"petya petrov","login":"my-login","email":"my@email.com","phone":"89223332211","avatar":"/path/to/my-file.jpg","role":"admin"} */
250 | export interface ChatUserResponse {
251 | /** User id */
252 | id: number;
253 | /** First name */
254 | first_name: string;
255 | /** Second name */
256 | second_name: string;
257 | /** Display name */
258 | display_name: string;
259 | /** User login - unique */
260 | login: string;
261 | /** Email */
262 | email: string;
263 | /** Phone */
264 | phone: string;
265 | /** Avatar */
266 | avatar: string;
267 | /** User role */
268 | role: "admin" | "regular";
269 | }
270 |
271 | export interface StaticChartRequest {
272 | /** Number of points in chart (10 / 100 / 1000) */
273 | chartSize: "small" | "medium" | "large";
274 | }
275 |
276 | export interface LiveChartRequest {
277 | /**
278 | * Works as a cursor (initial value should be zero, all the next values are taken from the backend response)
279 | * @format integer
280 | * @default 0
281 | */
282 | next: number;
283 | }
284 |
285 | export type ChartSchema = {
286 | /**
287 | * X axis (datetime)
288 | * @format date-time
289 | */
290 | x?: string;
291 | /** @format float */
292 | y1?: number;
293 | /** @format float */
294 | y2?: number;
295 | }[];
296 |
297 | export interface StaticChartResponse {
298 | /** Chart points */
299 | data?: ChartSchema;
300 | }
301 |
302 | export interface LiveChartResponse {
303 | /**
304 | * Used as a cursor (pass this value to the next request)
305 | * @example 5
306 | */
307 | next?: number;
308 | /** Chart points */
309 | data?: ChartSchema;
310 | }
311 |
312 | export interface LiveVideoInfoRequest {
313 | /**
314 | * Works as a cursor (iterate + 1 each request)
315 | * @format integer
316 | * @default 0
317 | */
318 | iteration: number;
319 | }
320 |
321 | export interface VideoInfoResponse {
322 | /**
323 | * Video size in bytes
324 | * @format integer
325 | * @example 4096
326 | */
327 | size: number;
328 | }
329 |
330 | export interface Sticker {
331 | /**
332 | * Sticker id (send to chat with WS)
333 | * @format integer
334 | * @example 123
335 | */
336 | id?: number;
337 | /**
338 | * Url for sticker resource(image)
339 | * @example "/stickers/2346-dfsg-425-sdfs/14534.gif"
340 | */
341 | path?: string;
342 | }
343 |
344 | export interface StickerPack {
345 | /**
346 | * Sticker pack title
347 | * @example "pack-title"
348 | */
349 | title?: string;
350 | /**
351 | * User id that created this pack
352 | * @format integer
353 | * @example 123
354 | */
355 | user_id?: number;
356 | stickers?: string[];
357 | }
358 |
359 | export interface StickerPacksResponse {
360 | /** StickerPacks */
361 | data?: StickerPack[];
362 | }
363 |
364 | export interface StickersResponse {
365 | /** Stickers */
366 | data?: Sticker[];
367 | }
368 |
369 | import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, HeadersDefaults, ResponseType } from "axios";
370 |
371 | export type QueryParamsType = Record;
372 |
373 | export interface FullRequestParams extends Omit {
374 | /** set parameter to `true` for call `securityWorker` for this request */
375 | secure?: boolean;
376 | /** request path */
377 | path: string;
378 | /** content type of request body */
379 | type?: ContentType;
380 | /** query params */
381 | query?: QueryParamsType;
382 | /** format of response (i.e. response.json() -> format: "json") */
383 | format?: ResponseType;
384 | /** request body */
385 | body?: unknown;
386 | }
387 |
388 | export type RequestParams = Omit;
389 |
390 | export interface ApiConfig extends Omit {
391 | securityWorker?: (
392 | securityData: SecurityDataType | null,
393 | ) => Promise | AxiosRequestConfig | void;
394 | secure?: boolean;
395 | format?: ResponseType;
396 | }
397 |
398 | export enum ContentType {
399 | Json = "application/json",
400 | FormData = "multipart/form-data",
401 | UrlEncoded = "application/x-www-form-urlencoded",
402 | }
403 |
404 | export class HttpClient {
405 | public instance: AxiosInstance;
406 | private securityData: SecurityDataType | null = null;
407 | private securityWorker?: ApiConfig["securityWorker"];
408 | private secure?: boolean;
409 | private format?: ResponseType;
410 |
411 | constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig = {}) {
412 | // this.instance = axios.create({
413 | // ...axiosConfig,
414 | // baseURL: axiosConfig.baseURL || "http://62.113.98.233:5000/api/v2",
415 | // });
416 | this.instance = axios.create({
417 | ...axiosConfig,
418 | baseURL: axiosConfig.baseURL || "/api/v2",
419 | });
420 | this.secure = secure;
421 | this.format = format;
422 | this.securityWorker = securityWorker;
423 | }
424 |
425 | public setSecurityData = (data: SecurityDataType | null) => {
426 | this.securityData = data;
427 | };
428 |
429 | protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig {
430 | const method = params1.method || (params2 && params2.method);
431 |
432 | return {
433 | ...this.instance.defaults,
434 | ...params1,
435 | ...(params2 || {}),
436 | headers: {
437 | ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}),
438 | ...(params1.headers || {}),
439 | ...((params2 && params2.headers) || {}),
440 | },
441 | };
442 | }
443 |
444 | protected stringifyFormItem(formItem: unknown) {
445 | if (typeof formItem === "object" && formItem !== null) {
446 | return JSON.stringify(formItem);
447 | } else {
448 | return `${formItem}`;
449 | }
450 | }
451 |
452 | protected createFormData(input: Record): FormData {
453 | return Object.keys(input || {}).reduce((formData, key) => {
454 | const property = input[key];
455 | const propertyContent: any[] = property instanceof Array ? property : [property];
456 |
457 | for (const formItem of propertyContent) {
458 | const isFileType = formItem instanceof Blob || formItem instanceof File;
459 | formData.append(key, isFileType ? formItem : this.stringifyFormItem(formItem));
460 | }
461 |
462 | return formData;
463 | }, new FormData());
464 | }
465 |
466 | public request = async ({
467 | secure,
468 | path,
469 | type,
470 | query,
471 | format,
472 | body,
473 | ...params
474 | }: FullRequestParams): Promise> => {
475 | const secureParams =
476 | ((typeof secure === "boolean" ? secure : this.secure) &&
477 | this.securityWorker &&
478 | (await this.securityWorker(this.securityData))) ||
479 | {};
480 | const requestParams = this.mergeRequestParams(params, secureParams);
481 | const responseFormat = format || this.format || undefined;
482 |
483 | if (type === ContentType.FormData && body && body !== null && typeof body === "object") {
484 | body = this.createFormData(body as Record);
485 | }
486 |
487 | return this.instance.request({
488 | ...requestParams,
489 | headers: {
490 | ...(requestParams.headers || {}),
491 | ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
492 | },
493 | params: query,
494 | responseType: responseFormat,
495 | data: body,
496 | url: path,
497 | });
498 | };
499 | }
500 |
501 | /**
502 | * @title Swagger
503 | * @version 1.0.0
504 | * @baseUrl http://62.113.98.233:5000/api/v2
505 | *
506 | * Chats API
507 | */
508 | export class Api extends HttpClient {
509 | auth = {
510 | /**
511 | * No description
512 | *
513 | * @tags Auth
514 | * @name SignupCreate
515 | * @summary Sign up (create user)
516 | * @request POST:/auth/signup
517 | * @response `200` `SignUpResponse` Ok
518 | * @response `400` `BadRequestError` Bad Request
519 | * @response `401` `void` Unauthorized
520 | * @response `500` `void` Unexpected error
521 | */
522 | signupCreate: (signUpRequest: SignUpRequest, params: RequestParams = {}) =>
523 | this.request({
524 | path: `/auth/signup`,
525 | method: "POST",
526 | body: signUpRequest,
527 | type: ContentType.Json,
528 | format: "json",
529 | ...params,
530 | }),
531 |
532 | /**
533 | * No description
534 | *
535 | * @tags Auth
536 | * @name SigninCreate
537 | * @summary Sign in
538 | * @request POST:/auth/signin
539 | * @response `200` `void` Ok
540 | * @response `400` `BadRequestError` Bad Request
541 | * @response `401` `void` Unauthorized
542 | * @response `500` `void` Unexpected error
543 | */
544 | signinCreate: (signInRequest: SignInRequest, params: RequestParams = {}) =>
545 | this.request({
546 | path: `/auth/signin`,
547 | method: "POST",
548 | body: signInRequest,
549 | type: ContentType.Json,
550 | ...params,
551 | }),
552 |
553 | /**
554 | * No description
555 | *
556 | * @tags Auth
557 | * @name UserList
558 | * @summary Get user info
559 | * @request GET:/auth/user
560 | * @response `200` `UserResponse` An array of user info
561 | * @response `400` `BadRequestError` Bad Request
562 | * @response `401` `void` Unauthorized
563 | * @response `500` `void` Unexpected error
564 | */
565 | userList: (params: RequestParams = {}) =>
566 | this.request({
567 | path: `/auth/user`,
568 | method: "GET",
569 | format: "json",
570 | ...params,
571 | }),
572 |
573 | /**
574 | * No description
575 | *
576 | * @tags Auth
577 | * @name LogoutCreate
578 | * @summary Logout
579 | * @request POST:/auth/logout
580 | * @response `200` `void` Ok
581 | * @response `500` `void` Unexpected error
582 | */
583 | logoutCreate: (params: RequestParams = {}) =>
584 | this.request({
585 | path: `/auth/logout`,
586 | method: "POST",
587 | ...params,
588 | }),
589 | };
590 | chats = {
591 | /**
592 | * No description
593 | *
594 | * @tags Chats
595 | * @name ChatsList
596 | * @summary Get chats
597 | * @request GET:/chats
598 | * @response `200` `(ChatsResponse)[]` Ok
599 | * @response `401` `void` Unauthorized
600 | * @response `500` `void` Unexpected error
601 | */
602 | chatsList: (
603 | query?: {
604 | /** The number of items to skip before starting to collect the result set */
605 | offset?: number;
606 | /** The numbers of items to return */
607 | limit?: number;
608 | /** Chat's title to filter by */
609 | title?: string;
610 | },
611 | params: RequestParams = {},
612 | ) =>
613 | this.request({
614 | path: `/chats`,
615 | method: "GET",
616 | query: query,
617 | format: "json",
618 | ...params,
619 | }),
620 |
621 | /**
622 | * No description
623 | *
624 | * @tags Chats
625 | * @name ChatsCreate
626 | * @summary Create chat
627 | * @request POST:/chats
628 | * @response `200` `void` Ok
629 | * @response `400` `BadRequestError` Bad Request
630 | * @response `401` `void` Unauthorized
631 | * @response `500` `void` Unexpected error
632 | */
633 | chatsCreate: (createChatRequest: CreateChatRequest, params: RequestParams = {}) =>
634 | this.request({
635 | path: `/chats`,
636 | method: "POST",
637 | body: createChatRequest,
638 | type: ContentType.Json,
639 | ...params,
640 | }),
641 |
642 | /**
643 | * @description Delete works only for admin role.
644 | *
645 | * @tags Chats
646 | * @name ChatsDelete
647 | * @summary Delete chat by ID
648 | * @request DELETE:/chats
649 | * @response `200` `ChatDeleteResponse` Ok
650 | * @response `400` `void` Bad Request
651 | * @response `401` `void` Unauthorized
652 | * @response `403` `void` Forbidden
653 | * @response `500` `void` Unexpected error
654 | */
655 | chatsDelete: (deleteChatRequest: ChatDeleteRequest, params: RequestParams = {}) =>
656 | this.request({
657 | path: `/chats`,
658 | method: "DELETE",
659 | body: deleteChatRequest,
660 | type: ContentType.Json,
661 | format: "json",
662 | ...params,
663 | }),
664 |
665 | /**
666 | * No description
667 | *
668 | * @tags Chats
669 | * @name ArchiveList
670 | * @summary Get archived chats
671 | * @request GET:/chats/archive
672 | * @response `200` `(ChatsResponse)[]` Ok
673 | * @response `401` `void` Unauthorized
674 | * @response `500` `void` Unexpected error
675 | */
676 | archiveList: (
677 | query?: {
678 | /** The number of items to skip before starting to collect the result set */
679 | offset?: number;
680 | /** The numbers of items to return */
681 | limit?: number;
682 | /** Chat's title to filter by */
683 | title?: string;
684 | },
685 | params: RequestParams = {},
686 | ) =>
687 | this.request({
688 | path: `/chats/archive`,
689 | method: "GET",
690 | query: query,
691 | format: "json",
692 | ...params,
693 | }),
694 |
695 | /**
696 | * @description Archive chat
697 | *
698 | * @tags Chats
699 | * @name ArchiveCreate
700 | * @summary Archive chat by ID
701 | * @request POST:/chats/archive
702 | * @response `200` `ChatArchiveResponse` Ok
703 | * @response `400` `void` Bad Request
704 | * @response `401` `void` Unauthorized
705 | * @response `403` `void` Forbidden
706 | * @response `500` `void` Unexpected error
707 | */
708 | archiveCreate: (archiveChatRequest: ChatArchiveRequest, params: RequestParams = {}) =>
709 | this.request({
710 | path: `/chats/archive`,
711 | method: "POST",
712 | body: archiveChatRequest,
713 | format: "json",
714 | ...params,
715 | }),
716 |
717 | /**
718 | * @description UnArchive chat
719 | *
720 | * @tags Chats
721 | * @name UnarchiveCreate
722 | * @summary UnArchive chat by ID
723 | * @request POST:/chats/unarchive
724 | * @response `200` `ChatArchiveResponse` Ok
725 | * @response `400` `void` Bad Request
726 | * @response `401` `void` Unauthorized
727 | * @response `403` `void` Forbidden
728 | * @response `500` `void` Unexpected error
729 | */
730 | unarchiveCreate: (unarchiveChatRequest: ChatArchiveRequest, params: RequestParams = {}) =>
731 | this.request({
732 | path: `/chats/unarchive`,
733 | method: "POST",
734 | body: unarchiveChatRequest,
735 | format: "json",
736 | ...params,
737 | }),
738 |
739 | /**
740 | * No description
741 | *
742 | * @tags Chats
743 | * @name CommonDetail
744 | * @summary Get common chat with current chat user (only works for two users chats)
745 | * @request GET:/chats/{id}/common
746 | * @response `200` `(ChatsResponse)[]` Ok
747 | * @response `400` `void` BadRequest
748 | * @response `401` `void` Unauthorized
749 | * @response `404` `void` Not found chat
750 | * @response `500` `void` Unexpected error
751 | */
752 | commonDetail: (id: number, params: RequestParams = {}) =>
753 | this.request({
754 | path: `/chats/${id}/common`,
755 | method: "GET",
756 | format: "json",
757 | ...params,
758 | }),
759 |
760 | /**
761 | * No description
762 | *
763 | * @tags Chats
764 | * @name UsersDetail
765 | * @summary Get chat users
766 | * @request GET:/chats/{id}/users
767 | * @response `200` `(ChatUserResponse)[]` Ok
768 | * @response `401` `void` Unauthorized
769 | * @response `404` `void` Not found chat
770 | * @response `500` `void` Unexpected error
771 | */
772 | usersDetail: (
773 | id: number,
774 | query?: {
775 | /** The number of items to skip before starting to collect the result set */
776 | offset?: number;
777 | /** The numbers of items to return */
778 | limit?: number;
779 | /** User's '{first_name} {second_name}' to filter */
780 | name?: string;
781 | /** User's email to filter */
782 | email?: string;
783 | },
784 | params: RequestParams = {},
785 | ) =>
786 | this.request({
787 | path: `/chats/${id}/users`,
788 | method: "GET",
789 | query: query,
790 | format: "json",
791 | ...params,
792 | }),
793 |
794 | /**
795 | * No description
796 | *
797 | * @tags Chats
798 | * @name GetChats
799 | * @summary Get new messages count
800 | * @request GET:/chats/new/{id}
801 | * @response `200` `UnreadCountResponse` Ok
802 | * @response `401` `void` Unauthorized
803 | * @response `500` `void` Unexpected error
804 | */
805 | getChats: (id: number, params: RequestParams = {}) =>
806 | this.request({
807 | path: `/chats/new/${id}`,
808 | method: "GET",
809 | format: "json",
810 | ...params,
811 | }),
812 |
813 | /**
814 | * No description
815 | *
816 | * @tags Chats
817 | * @name UsersUpdate
818 | * @summary Add users to chat
819 | * @request PUT:/chats/users
820 | * @response `200` `void` Ok
821 | * @response `400` `BadRequestError` Bad Request
822 | * @response `401` `void` Unauthorized
823 | * @response `500` `void` Unexpected error
824 | */
825 | usersUpdate: (usersRequest: UsersRequest, params: RequestParams = {}) =>
826 | this.request({
827 | path: `/chats/users`,
828 | method: "PUT",
829 | body: usersRequest,
830 | ...params,
831 | }),
832 |
833 | /**
834 | * No description
835 | *
836 | * @tags Chats
837 | * @name UsersDelete
838 | * @summary Delete users from chat
839 | * @request DELETE:/chats/users
840 | * @response `200` `void` Ok
841 | * @response `400` `BadRequestError` Bad Request
842 | * @response `401` `void` Unauthorized
843 | * @response `500` `void` Unexpected error
844 | */
845 | usersDelete: (usersRequest: UsersRequest, params: RequestParams = {}) =>
846 | this.request({
847 | path: `/chats/users`,
848 | method: "DELETE",
849 | body: usersRequest,
850 | ...params,
851 | }),
852 |
853 | /**
854 | * @description Request token to connect to messages server
855 | *
856 | * @tags Chats
857 | * @name TokenCreate
858 | * @summary Get chat users
859 | * @request POST:/chats/token/{id}
860 | * @response `200` `(ChatsMessagesTokenResponse)[]` Ok
861 | * @response `401` `void` Unauthorized
862 | * @response `500` `void` Unexpected error
863 | */
864 | tokenCreate: (id: number, params: RequestParams = {}) =>
865 | this.request({
866 | path: `/chats/token/${id}`,
867 | method: "POST",
868 | format: "json",
869 | ...params,
870 | }),
871 | };
872 | oauth = {
873 | /**
874 | * No description
875 | *
876 | * @tags Oauth
877 | * @name YandexCreate
878 | * @summary Sign in / sign up with yandex
879 | * @request POST:/oauth/yandex
880 | * @response `200` `void` Ok
881 | * @response `400` `BadRequestError` Bad Request (No such redirect_uri or wrong code)
882 | * @response `401` `void` Unauthorized
883 | * @response `500` `void` Unexpected error
884 | */
885 | yandexCreate: (OauthSignInRequest: OauthSignInRequest, params: RequestParams = {}) =>
886 | this.request({
887 | path: `/oauth/yandex`,
888 | method: "POST",
889 | body: OauthSignInRequest,
890 | type: ContentType.Json,
891 | ...params,
892 | }),
893 |
894 | /**
895 | * No description
896 | *
897 | * @tags Oauth
898 | * @name YandexServiceIdList
899 | * @summary Get service id
900 | * @request GET:/oauth/yandex/service-id
901 | * @response `200` `ServiceId` Yandex client id
902 | * @response `400` `BadRequestError` Bad Request (No such redirect_uri refistered)
903 | * @response `500` `void` Unexpected error
904 | */
905 | yandexServiceIdList: (
906 | query?: {
907 | /** Redirect uri that you are using for oauth */
908 | redirect_uri?: string;
909 | },
910 | params: RequestParams = {},
911 | ) =>
912 | this.request({
913 | path: `/oauth/yandex/service-id`,
914 | method: "GET",
915 | query: query,
916 | format: "json",
917 | ...params,
918 | }),
919 | };
920 | user = {
921 | /**
922 | * No description
923 | *
924 | * @tags Users
925 | * @name ProfileUpdate
926 | * @summary Change user profile
927 | * @request PUT:/user/profile
928 | * @response `200` `UserResponse` Ok
929 | * @response `400` `BadRequestError` Bad Request
930 | * @response `401` `void` Unauthorized
931 | * @response `500` `void` Unexpected error
932 | */
933 | profileUpdate: (userRequest: UserUpdateRequest, params: RequestParams = {}) =>
934 | this.request({
935 | path: `/user/profile`,
936 | method: "PUT",
937 | body: userRequest,
938 | type: ContentType.Json,
939 | format: "json",
940 | ...params,
941 | }),
942 |
943 | /**
944 | * No description
945 | *
946 | * @tags Users
947 | * @name ProfileAvatarUpdate
948 | * @summary Change user avatar
949 | * @request PUT:/user/profile/avatar
950 | * @response `200` `UserResponse` Ok
951 | * @response `400` `BadRequestError` Bad Request
952 | * @response `401` `void` Unauthorized
953 | * @response `500` `void` Unexpected error
954 | */
955 | profileAvatarUpdate: (
956 | data: {
957 | /**
958 | * Avatar
959 | * @format binary
960 | */
961 | avatar: File;
962 | },
963 | params: RequestParams = {},
964 | ) =>
965 | this.request({
966 | path: `/user/profile/avatar`,
967 | method: "PUT",
968 | body: data,
969 | type: ContentType.FormData,
970 | format: "json",
971 | ...params,
972 | }),
973 |
974 | /**
975 | * No description
976 | *
977 | * @tags Users
978 | * @name PasswordUpdate
979 | * @summary Change user password
980 | * @request PUT:/user/password
981 | * @response `200` `void` Ok
982 | * @response `400` `BadRequestError` Bad Request
983 | * @response `401` `void` Unauthorized
984 | * @response `500` `void` Unexpected error
985 | */
986 | passwordUpdate: (changePasswordRequest: ChangePasswordRequest, params: RequestParams = {}) =>
987 | this.request({
988 | path: `/user/password`,
989 | method: "PUT",
990 | body: changePasswordRequest,
991 | type: ContentType.Json,
992 | ...params,
993 | }),
994 |
995 | /**
996 | * No description
997 | *
998 | * @tags Users
999 | * @name UserDetail
1000 | * @summary Get user by id
1001 | * @request GET:/user/{id}
1002 | * @response `200` `UserResponse` Ok
1003 | * @response `401` `void` Unauthorized
1004 | * @response `500` `void` Unexpected error
1005 | */
1006 | userDetail: (id: number, params: RequestParams = {}) =>
1007 | this.request({
1008 | path: `/user/${id}`,
1009 | method: "GET",
1010 | format: "json",
1011 | ...params,
1012 | }),
1013 |
1014 | /**
1015 | * No description
1016 | *
1017 | * @tags Users
1018 | * @name SearchCreate
1019 | * @summary Search for user by login (max 10)
1020 | * @request POST:/user/search
1021 | * @response `200` `(UserResponse)[]` Ok
1022 | * @response `400` `BadRequestError` Bad Request
1023 | * @response `401` `void` Unauthorized
1024 | * @response `500` `void` Unexpected error
1025 | */
1026 | searchCreate: (findUserRequest: FindUserRequest, params: RequestParams = {}) =>
1027 | this.request({
1028 | path: `/user/search`,
1029 | method: "POST",
1030 | body: findUserRequest,
1031 | type: ContentType.Json,
1032 | format: "json",
1033 | ...params,
1034 | }),
1035 | };
1036 | }
1037 |
--------------------------------------------------------------------------------
/src/api/base/swagger.yaml:
--------------------------------------------------------------------------------
1 | info:
2 | description: Chats API
3 | title: Swagger
4 | version: 1.0.0
5 | host: 62.113.98.233:5000
6 | basePath: /api/v2
7 | produces:
8 | - application/json
9 | - application/xml
10 | schemes:
11 | - http
12 | swagger: '2.0'
13 | paths:
14 | /auth/signup:
15 | post:
16 | parameters:
17 | - name: signUpRequest
18 | in: body
19 | description: User data
20 | required: true
21 | schema:
22 | $ref: '#/definitions/SignUpRequest'
23 | description: ''
24 | tags:
25 | - Auth
26 | responses:
27 | '200':
28 | description: Ok
29 | schema:
30 | $ref: '#/definitions/SignUpResponse'
31 | '400':
32 | description: Bad Request
33 | schema:
34 | $ref: '#/definitions/BadRequestError'
35 | '401':
36 | description: Unauthorized
37 | '500':
38 | description: Unexpected error
39 | summary: Sign up (create user)
40 | /auth/signin:
41 | post:
42 | parameters:
43 | - name: signInRequest
44 | in: body
45 | description: User data
46 | required: true
47 | schema:
48 | $ref: '#/definitions/SignInRequest'
49 | description: ''
50 | tags:
51 | - Auth
52 | responses:
53 | '200':
54 | description: Ok
55 | '400':
56 | description: Bad Request
57 | schema:
58 | $ref: '#/definitions/BadRequestError'
59 | '401':
60 | description: Unauthorized
61 | '500':
62 | description: Unexpected error
63 | summary: Sign in
64 | /auth/user:
65 | get:
66 | parameters: []
67 | description: ''
68 | tags:
69 | - Auth
70 | responses:
71 | '200':
72 | description: An array of user info
73 | schema:
74 | $ref: '#/definitions/UserResponse'
75 | '400':
76 | description: Bad Request
77 | schema:
78 | $ref: '#/definitions/BadRequestError'
79 | '401':
80 | description: Unauthorized
81 | '500':
82 | description: Unexpected error
83 | summary: Get user info
84 | /auth/logout:
85 | post:
86 | parameters: []
87 | description: ''
88 | tags:
89 | - Auth
90 | responses:
91 | '200':
92 | description: Ok
93 | '500':
94 | description: Unexpected error
95 | summary: Logout
96 |
97 | /chats:
98 | get:
99 | parameters:
100 | - in: query
101 | name: offset
102 | schema:
103 | type: integer
104 | description: The number of items to skip before starting to collect the result set
105 | - in: query
106 | name: limit
107 | schema:
108 | type: integer
109 | description: The numbers of items to return
110 | - in: query
111 | name: title
112 | schema:
113 | type: string
114 | description: Chat's title to filter by
115 | description: ''
116 | tags:
117 | - Chats
118 | responses:
119 | '200':
120 | description: Ok
121 | schema:
122 | type: array
123 | items:
124 | $ref: '#/definitions/ChatsResponse'
125 | '401':
126 | description: Unauthorized
127 | '500':
128 | description: Unexpected error
129 | summary: Get chats
130 | post:
131 | parameters:
132 | - name: createChatRequest
133 | in: body
134 | description: Chat data
135 | required: true
136 | schema:
137 | $ref: '#/definitions/CreateChatRequest'
138 | description: ''
139 | tags:
140 | - Chats
141 | responses:
142 | '200':
143 | description: Ok
144 | '400':
145 | description: Bad Request
146 | schema:
147 | $ref: '#/definitions/BadRequestError'
148 | '401':
149 | description: Unauthorized
150 | '500':
151 | description: Unexpected error
152 | summary: Create chat
153 | delete:
154 | parameters:
155 | - name: deleteChatRequest
156 | in: body
157 | description: ''
158 | required: true
159 | schema:
160 | $ref: '#/definitions/ChatDeleteRequest'
161 | description: 'Delete works only for admin role.'
162 | tags:
163 | - Chats
164 | responses:
165 | '200':
166 | description: Ok
167 | schema:
168 | $ref: '#/definitions/ChatDeleteResponse'
169 | '400':
170 | description: Bad Request
171 | '401':
172 | description: Unauthorized
173 | '403':
174 | description: Forbidden
175 | '500':
176 | description: Unexpected error
177 | summary: Delete chat by ID
178 |
179 | /chats/archive:
180 | get:
181 | parameters:
182 | - in: query
183 | name: offset
184 | schema:
185 | type: integer
186 | description: The number of items to skip before starting to collect the result set
187 | - in: query
188 | name: limit
189 | schema:
190 | type: integer
191 | description: The numbers of items to return
192 | - in: query
193 | name: title
194 | schema:
195 | type: string
196 | description: Chat's title to filter by
197 | description: ''
198 | tags:
199 | - Chats
200 | responses:
201 | '200':
202 | description: Ok
203 | schema:
204 | type: array
205 | items:
206 | $ref: '#/definitions/ChatsResponse'
207 | '401':
208 | description: Unauthorized
209 | '500':
210 | description: Unexpected error
211 | summary: Get archived chats
212 | post:
213 | parameters:
214 | - name: archiveChatRequest
215 | in: body
216 | description: ''
217 | required: true
218 | schema:
219 | $ref: '#/definitions/ChatArchiveRequest'
220 | description: 'Archive chat'
221 | tags:
222 | - Chats
223 | responses:
224 | '200':
225 | description: Ok
226 | schema:
227 | $ref: '#/definitions/ChatArchiveResponse'
228 | '400':
229 | description: Bad Request
230 | '401':
231 | description: Unauthorized
232 | '403':
233 | description: Forbidden
234 | '500':
235 | description: Unexpected error
236 | summary: Archive chat by ID
237 |
238 | /chats/unarchive:
239 | post:
240 | parameters:
241 | - name: unarchiveChatRequest
242 | in: body
243 | description: ''
244 | required: true
245 | schema:
246 | $ref: '#/definitions/ChatArchiveRequest'
247 | description: 'UnArchive chat'
248 | tags:
249 | - Chats
250 | responses:
251 | '200':
252 | description: Ok
253 | schema:
254 | $ref: '#/definitions/ChatArchiveResponse'
255 | '400':
256 | description: Bad Request
257 | '401':
258 | description: Unauthorized
259 | '403':
260 | description: Forbidden
261 | '500':
262 | description: Unexpected error
263 | summary: UnArchive chat by ID
264 |
265 | /chats/{id}/common:
266 | get:
267 | parameters:
268 | - in: path
269 | name: id
270 | schema:
271 | type: integer
272 | required: true
273 | description: Numeric chat id
274 | description: ''
275 | tags:
276 | - Chats
277 | responses:
278 | '200':
279 | description: Ok
280 | schema:
281 | type: array
282 | items:
283 | $ref: '#/definitions/ChatsResponse'
284 | '400':
285 | description: BadRequest
286 | '401':
287 | description: Unauthorized
288 | '404':
289 | description: Not found chat
290 | '500':
291 | description: Unexpected error
292 | summary: Get common chat with current chat user (only works for two users chats)
293 |
294 | /chats/{id}/users:
295 | get:
296 | parameters:
297 | - in: path
298 | name: id
299 | schema:
300 | type: integer
301 | required: true
302 | description: Numeric chat id
303 | - in: query
304 | name: offset
305 | schema:
306 | type: integer
307 | description: The number of items to skip before starting to collect the result set
308 | - in: query
309 | name: limit
310 | schema:
311 | type: integer
312 | description: The numbers of items to return
313 | - in: query
314 | name: name
315 | schema:
316 | type: string
317 | description: User's '{first_name} {second_name}' to filter
318 | - in: query
319 | name: email
320 | schema:
321 | type: string
322 | description: User's email to filter
323 | description: ''
324 | tags:
325 | - Chats
326 | responses:
327 | '200':
328 | description: Ok
329 | schema:
330 | type: array
331 | items:
332 | $ref: '#/definitions/ChatUserResponse'
333 | '401':
334 | description: Unauthorized
335 | '404':
336 | description: Not found chat
337 | '500':
338 | description: Unexpected error
339 | summary: Get chat users
340 |
341 | /chats/new/{id}:
342 | get:
343 | parameters:
344 | - in: path
345 | name: id
346 | schema:
347 | type: integer
348 | required: true
349 | description: Numeric chat id
350 | description: ''
351 | tags:
352 | - Chats
353 | responses:
354 | '200':
355 | description: Ok
356 | schema:
357 | $ref: '#/definitions/UnreadCountResponse'
358 | '401':
359 | description: Unauthorized
360 | '500':
361 | description: Unexpected error
362 | summary: Get new messages count
363 | /chats/users:
364 | put:
365 | parameters:
366 | - name: usersRequest
367 | in: body
368 | description: ''
369 | required: true
370 | schema:
371 | $ref: '#/definitions/UsersRequest'
372 | description: ''
373 | tags:
374 | - Chats
375 | responses:
376 | '200':
377 | description: Ok
378 | '400':
379 | description: Bad Request
380 | schema:
381 | $ref: '#/definitions/BadRequestError'
382 | '401':
383 | description: Unauthorized
384 | '500':
385 | description: Unexpected error
386 | summary: Add users to chat
387 | delete:
388 | parameters:
389 | - name: usersRequest
390 | in: body
391 | description: ''
392 | required: true
393 | schema:
394 | $ref: '#/definitions/UsersRequest'
395 | description: ''
396 | tags:
397 | - Chats
398 | responses:
399 | '200':
400 | description: Ok
401 | '400':
402 | description: Bad Request
403 | schema:
404 | $ref: '#/definitions/BadRequestError'
405 | '401':
406 | description: Unauthorized
407 | '500':
408 | description: Unexpected error
409 | summary: Delete users from chat
410 |
411 | /chats/token/{id}:
412 | post:
413 | parameters:
414 | - in: path
415 | name: id
416 | schema:
417 | type: integer
418 | required: true
419 | description: Numeric chat id
420 | description: 'Request token to connect to messages server'
421 | tags:
422 | - Chats
423 | responses:
424 | '200':
425 | description: Ok
426 | schema:
427 | type: array
428 | items:
429 | $ref: '#/definitions/ChatsMessagesTokenResponse'
430 | '401':
431 | description: Unauthorized
432 | '500':
433 | description: Unexpected error
434 | summary: Get chat users
435 | /oauth/yandex:
436 | post:
437 | parameters:
438 | - name: OauthSignInRequest
439 | in: body
440 | description: Oauth data
441 | required: true
442 | schema:
443 | $ref: '#/definitions/OauthSignInRequest'
444 | description: ''
445 | tags:
446 | - Oauth
447 | responses:
448 | '200':
449 | description: Ok
450 | '400':
451 | description: Bad Request (No such redirect_uri or wrong code)
452 | schema:
453 | $ref: '#/definitions/BadRequestError'
454 | '401':
455 | description: Unauthorized
456 | '500':
457 | description: Unexpected error
458 | summary: Sign in / sign up with yandex
459 | /oauth/yandex/service-id:
460 | get:
461 | parameters:
462 | - in: query
463 | name: redirect_uri
464 | schema:
465 | type: string
466 | description: Redirect uri that you are using for oauth
467 | description: ''
468 | tags:
469 | - Oauth
470 | responses:
471 | '200':
472 | description: Yandex client id
473 | schema:
474 | $ref: '#/definitions/ServiceId'
475 | '400':
476 | description: Bad Request (No such redirect_uri refistered)
477 | schema:
478 | $ref: '#/definitions/BadRequestError'
479 | '500':
480 | description: Unexpected error
481 | summary: Get service id
482 | /user/profile:
483 | put:
484 | parameters:
485 | - name: userRequest
486 | in: body
487 | description: User data
488 | required: true
489 | schema:
490 | $ref: '#/definitions/UserUpdateRequest'
491 | description: ''
492 | tags:
493 | - Users
494 | responses:
495 | '200':
496 | description: Ok
497 | schema:
498 | $ref: '#/definitions/UserResponse'
499 | '400':
500 | description: Bad Request
501 | schema:
502 | $ref: '#/definitions/BadRequestError'
503 | '401':
504 | description: Unauthorized
505 | '500':
506 | description: Unexpected error
507 | summary: Change user profile
508 | /user/profile/avatar:
509 | put:
510 | parameters:
511 | - name: avatar
512 | in: formData
513 | description: Avatar
514 | required: true
515 | type: file
516 | consumes: ['multipart/form-data']
517 | description: ''
518 | tags:
519 | - Users
520 | responses:
521 | '200':
522 | description: Ok
523 | schema:
524 | $ref: '#/definitions/UserResponse'
525 | '400':
526 | description: Bad Request
527 | schema:
528 | $ref: '#/definitions/BadRequestError'
529 | '401':
530 | description: Unauthorized
531 | '500':
532 | description: Unexpected error
533 | summary: Change user avatar
534 | /user/password:
535 | put:
536 | parameters:
537 | - name: changePasswordRequest
538 | in: body
539 | description: Password request
540 | required: true
541 | schema:
542 | $ref: '#/definitions/ChangePasswordRequest'
543 | description: ''
544 | tags:
545 | - Users
546 | responses:
547 | '200':
548 | description: Ok
549 | '400':
550 | description: Bad Request
551 | schema:
552 | $ref: '#/definitions/BadRequestError'
553 | '401':
554 | description: Unauthorized
555 | '500':
556 | description: Unexpected error
557 | summary: Change user password
558 | /user/{id}:
559 | get:
560 | parameters:
561 | - in: path
562 | name: id
563 | schema:
564 | type: integer
565 | required: true
566 | description: Numeric user id
567 | description: ''
568 | tags:
569 | - Users
570 | responses:
571 | '200':
572 | description: Ok
573 | schema:
574 | $ref: '#/definitions/UserResponse'
575 | '401':
576 | description: Unauthorized
577 | '500':
578 | description: Unexpected error
579 | summary: Get user by id
580 | /user/search:
581 | post:
582 | parameters:
583 | - name: findUserRequest
584 | in: body
585 | description: User data
586 | required: true
587 | schema:
588 | $ref: '#/definitions/FindUserRequest'
589 | description: ''
590 | tags:
591 | - Users
592 | responses:
593 | '200':
594 | description: Ok
595 | schema:
596 | type: array
597 | items:
598 | $ref: '#/definitions/UserResponse'
599 | '400':
600 | description: Bad Request
601 | schema:
602 | $ref: '#/definitions/BadRequestError'
603 | '401':
604 | description: Unauthorized
605 | '500':
606 | description: Unexpected error
607 | summary: Search for user by login (max 10)
608 |
609 | definitions:
610 | UserResponse:
611 | example:
612 | id: 123
613 | first_name: Petya
614 | second_name: Pupkin
615 | display_name: Petya Pupkin
616 | login: userLogin
617 | email: my@email.com
618 | phone: "89223332211"
619 | avatar: /path/to/avatar.jpg
620 | required:
621 | - id
622 | - first_name
623 | - second_name
624 | - display_name
625 | - login
626 | - email
627 | - phone
628 | - avatar
629 | properties:
630 | id:
631 | type: integer
632 | description: User id
633 | first_name:
634 | type: string
635 | description: First name
636 | second_name:
637 | type: string
638 | description: Second name
639 | display_name:
640 | type: string
641 | description: Display name
642 | login:
643 | type: string
644 | description: User login - unique
645 | email:
646 | type: string
647 | description: Email
648 | phone:
649 | type: string
650 | description: Phone
651 | avatar:
652 | type: string
653 | description: Avatar
654 | SignUpRequest:
655 | required:
656 | - first_name
657 | - second_name
658 | - login
659 | - email
660 | - password
661 | - phone
662 | properties:
663 | first_name:
664 | type: string
665 | description: First name
666 | second_name:
667 | type: string
668 | description: Second name
669 | login:
670 | type: string
671 | description: User login - unique
672 | email:
673 | type: string
674 | description: Email /^\S+@\S+$/
675 | password:
676 | type: string
677 | description: Password
678 | phone:
679 | type: string
680 | description: 'Phone /^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$/'
681 | SignInRequest:
682 | required:
683 | - login
684 | - password
685 | properties:
686 | login:
687 | type: string
688 | description: User login
689 | password:
690 | type: string
691 | description: Password
692 | SignUpResponse:
693 | required:
694 | - id
695 | properties:
696 | id:
697 | type: number
698 | description: Created User ID
699 | CreateChatRequest:
700 | required:
701 | - title
702 | properties:
703 | title:
704 | type: string
705 | description: Chat title
706 | UsersRequest:
707 | required:
708 | - users
709 | - chatId
710 | properties:
711 | users:
712 | type: array
713 | items:
714 | type: integer
715 | chatId:
716 | type: integer
717 | description: Chat id
718 | ChatsResponse:
719 | example:
720 | id: 123
721 | title: my-chat
722 | avatar: /123/avatar1.jpg
723 | unread_count: 15
724 | last_message:
725 | user:
726 | first_name: Petya
727 | second_name: Pupkin
728 | avatar: /path/to/avatar.jpg
729 | email: my@email.com
730 | login: userLogin
731 | phone: 8(911)-222-33-22
732 | time: 2020-01-02 14:22:22Z
733 | content: this is message content
734 | required:
735 | - id
736 | - title
737 | - avatar
738 | - unread_count
739 | - last_message
740 | properties:
741 | id:
742 | type: integer
743 | description: Chat id
744 | title:
745 | type: string
746 | description: Chat title
747 | avatar:
748 | type: string
749 | description: Chat avatar
750 | unread_count:
751 | type: integer
752 | description: Number of unread messages in chat for current user
753 | last_message:
754 | type: object
755 | properties:
756 | user:
757 | type: object
758 | $ref: '#/definitions/UserResponse'
759 | format: date-time
760 | description: Message user (sender)
761 | time:
762 | type: string
763 | format: timestamp
764 | description: Message timestamp
765 | content:
766 | type: string
767 | description: Message content
768 |
769 | ChatDeleteRequest:
770 | required:
771 | - chatId
772 | properties:
773 | chatId:
774 | type: integer
775 | description: Chat id
776 | ChatDeleteResponse:
777 | example:
778 | userId: 12
779 | result:
780 | id: 123
781 | title: deleted-chat
782 | avatar: /123/avatar1.jpg
783 | required:
784 | - userId
785 | - result
786 | properties:
787 | userId:
788 | type: integer
789 | description: User id
790 | result:
791 | type: object
792 | $ref: '#/definitions/ChatsResponse'
793 | ChatArchiveRequest:
794 | required:
795 | - chatId
796 | properties:
797 | chatId:
798 | type: integer
799 | description: Chat id
800 | ChatArchiveResponse:
801 | required:
802 | - userId
803 | - result
804 | properties:
805 | userId:
806 | type: integer
807 | description: User id
808 | result:
809 | type: object
810 | $ref: '#/definitions/ChatsResponse'
811 | ChatsMessagesTokenResponse:
812 | required:
813 | - token
814 | properties:
815 | token:
816 | type: string
817 | description: Token for web socket server
818 | UnreadCountResponse:
819 | example:
820 | unread_count: 12
821 | required:
822 | - unread_count
823 | properties:
824 | unread_count:
825 | type: integer
826 | description: New messages count
827 | LeaderboardNewLeaderRequest:
828 | required:
829 | - data
830 | - ratingFieldName
831 | properties:
832 | data:
833 | type: object
834 | description: 'Leaderboard data object, any type'
835 | ratingFieldName:
836 | type: string
837 | description: >-
838 | Which field is used to sort (if new value of the field more than old,
839 | data is stored)
840 | teamName:
841 | type: string
842 | description: >-
843 | Your team name. Used to make unique leaderboard for each project.
844 | LeaderboardRequest:
845 | required:
846 | - ratingFieldName
847 | - cursor
848 | - limit
849 | properties:
850 | ratingFieldName:
851 | type: string
852 | description: Which field is used to sort
853 | cursor:
854 | type: integer
855 | description: Used to paginate between pages. If limit is 10, then for the 1st page - cursor=0, for the 2nd page - cursor=10.
856 | limit:
857 | type: integer
858 | description: Maximum amount of leaders to return
859 | OauthSignInRequest:
860 | required:
861 | - code
862 | - redirect_uri
863 | properties:
864 | code:
865 | type: string
866 | description: User code from Yandex
867 | redirect_uri:
868 | type: string
869 | description: Redirect uri that you are using for oauth
870 | ServiceId:
871 | required:
872 | - service_id
873 | properties:
874 | service_id:
875 | type: string
876 | description: Service id
877 | BadRequestError:
878 | required:
879 | - reason
880 | properties:
881 | reason:
882 | type: string
883 | description: Error message
884 | UserUpdateRequest:
885 | required:
886 | - first_name
887 | - second_name
888 | - display_name
889 | - phone
890 | - login
891 | - email
892 | properties:
893 | first_name:
894 | type: string
895 | description: First name
896 | second_name:
897 | type: string
898 | description: Second name
899 | display_name:
900 | type: string
901 | description: Display Name
902 | login:
903 | type: string
904 | description: User login - unique
905 | email:
906 | type: string
907 | description: Email
908 | phone:
909 | type: string
910 | description: Phone
911 | UserRequest:
912 | required:
913 | - first_name
914 | - second_name
915 | - display_name
916 | - phone
917 | - login
918 | - email
919 | properties:
920 | first_name:
921 | type: string
922 | description: First name
923 | second_name:
924 | type: string
925 | description: Second name
926 | display_name:
927 | type: string
928 | description: Display Name
929 | login:
930 | type: string
931 | description: User login - unique
932 | email:
933 | type: string
934 | description: Email
935 | phone:
936 | type: string
937 | description: Phone
938 | FindUserRequest:
939 | required:
940 | - login
941 | properties:
942 | login:
943 | type: string
944 | description: User login (beginning of login)
945 | ChangePasswordRequest:
946 | required:
947 | - oldPassword
948 | - newPassword
949 | properties:
950 | oldPassword:
951 | type: string
952 | description: Old password
953 | newPassword:
954 | type: string
955 | description: New password
956 | Resource:
957 | example:
958 | id: 123
959 | user_id: 231
960 | path: /32543654dsf/434534r3rsddfs_my-file.jpg
961 | filename: my-file.jpg
962 | content_type: image/jpeg
963 | content_size: 543672
964 | upload_date: 2020-01-02 14:22:22Z
965 | required:
966 | - id
967 | - user_id
968 | - path
969 | - filename
970 | - content_type
971 | - content_size
972 | - upload_date
973 | properties:
974 | id:
975 | type: integer
976 | description: Message id
977 | user_id:
978 | type: integer
979 | description: User id
980 | path:
981 | type: string
982 | description: Server relative file path
983 | filename:
984 | type: string
985 | description: Initial file name
986 | content_type:
987 | type: string
988 | description: File content type (e.g "image/jpeg" for .jpg images)
989 | content_size:
990 | type: integer
991 | description: File size in bytes
992 | upload_date:
993 | type: string
994 | format: date-time
995 | description: Resource uploading time
996 |
997 | ChatMessage:
998 | example:
999 | id: 123
1000 | user_id: 231
1001 | chat_id: 312
1002 | time: 2020-01-02 14:22:22Z
1003 | type: file
1004 | content: 132
1005 | file:
1006 | id: 132
1007 | user_id: 231
1008 | path: /32543654dsf/434534r3rsddfs_my-file.jpg
1009 | filename: my-file.jpg
1010 | content_type: image/jpeg
1011 | content_size: 543672
1012 | upload_date: 2020-01-02 14:22:22Z
1013 | required:
1014 | - id
1015 | - user_id
1016 | - chat_id
1017 | - time
1018 | - type
1019 | - content
1020 | properties:
1021 | id:
1022 | type: integer
1023 | description: Message id
1024 | user_id:
1025 | type: integer
1026 | description: User id
1027 | chat_id:
1028 | type: integer
1029 | description: Chat id
1030 | time:
1031 | type: string
1032 | format: date-time
1033 | description: Message sent time
1034 | type:
1035 | type: string
1036 | enum: [ message, file ]
1037 | description: Message type
1038 | content:
1039 | type: string
1040 | description: Message content (message text for messages and resourceId for files)
1041 | file:
1042 | $ref: '#/definitions/Resource'
1043 | description: File
1044 | ChatUserResponse:
1045 | example:
1046 | id: 123
1047 | first_name: petya
1048 | second_name: petrov
1049 | display_name: petya petrov
1050 | login: my-login
1051 | email: my@email.com
1052 | phone: "89223332211"
1053 | avatar: /path/to/my-file.jpg
1054 | role: admin
1055 | required:
1056 | - id
1057 | - first_name
1058 | - second_name
1059 | - display_name
1060 | - login
1061 | - email
1062 | - phone
1063 | - avatar
1064 | - role
1065 | properties:
1066 | id:
1067 | type: integer
1068 | description: User id
1069 | first_name:
1070 | type: string
1071 | description: First name
1072 | second_name:
1073 | type: string
1074 | description: Second name
1075 | display_name:
1076 | type: string
1077 | description: Display name
1078 | login:
1079 | type: string
1080 | description: User login - unique
1081 | email:
1082 | type: string
1083 | description: Email
1084 | phone:
1085 | type: string
1086 | description: Phone
1087 | avatar:
1088 | type: string
1089 | description: Avatar
1090 | role:
1091 | type: string
1092 | enum: [admin, regular]
1093 | description: User role
1094 | StaticChartRequest:
1095 | required:
1096 | - chartSize
1097 | properties:
1098 | chartSize:
1099 | type: string
1100 | description: Number of points in chart (10 / 100 / 1000)
1101 | enum: [ small, medium, large ]
1102 | LiveChartRequest:
1103 | required:
1104 | - next
1105 | properties:
1106 | next:
1107 | type: number
1108 | format: integer
1109 | default: 0
1110 | description: Works as a cursor (initial value should be zero, all the next values are taken from the backend response)
1111 | ChartSchema:
1112 | type: array
1113 | items:
1114 | type: object
1115 | properties:
1116 | x:
1117 | type: string
1118 | format: date-time
1119 | description: X axis (datetime)
1120 | y1:
1121 | type: number
1122 | format: float
1123 | y2:
1124 | type: number
1125 | format: float
1126 | StaticChartResponse:
1127 | properties:
1128 | data:
1129 | $ref: '#/definitions/ChartSchema'
1130 | description: Chart points
1131 | LiveChartResponse:
1132 | properties:
1133 | next:
1134 | type: integer
1135 | example: 5
1136 | description: Used as a cursor (pass this value to the next request)
1137 | data:
1138 | $ref: '#/definitions/ChartSchema'
1139 | description: Chart points
1140 | LiveVideoInfoRequest:
1141 | required:
1142 | - iteration
1143 | properties:
1144 | iteration:
1145 | type: number
1146 | format: integer
1147 | default: 0
1148 | description: Works as a cursor (iterate + 1 each request)
1149 | VideoInfoResponse:
1150 | required:
1151 | - size
1152 | properties:
1153 | size:
1154 | type: number
1155 | format: integer
1156 | example: 4096
1157 | description: Video size in bytes
1158 | Sticker:
1159 | type: object
1160 | properties:
1161 | id:
1162 | type: number
1163 | format: integer
1164 | example: 123
1165 | description: Sticker id (send to chat with WS)
1166 | path:
1167 | type: string
1168 | example: /stickers/2346-dfsg-425-sdfs/14534.gif
1169 | description: Url for sticker resource(image)
1170 | StickerPack:
1171 | type: object
1172 | properties:
1173 | title:
1174 | type: string
1175 | example: pack-title
1176 | description: Sticker pack title
1177 | user_id:
1178 | type: number
1179 | format: integer
1180 | example: 123
1181 | description: User id that created this pack
1182 | stickers:
1183 | type: array
1184 | items:
1185 | type: string
1186 | example: /stickers/2346-dfsg-425-sdfs/14534.gif
1187 | description: Url for sticker resource(image)
1188 | StickerPacksResponse:
1189 | properties:
1190 | data:
1191 | type: array
1192 | items:
1193 | $ref: '#/definitions/StickerPack'
1194 | description: StickerPacks
1195 | StickersResponse:
1196 | properties:
1197 | data:
1198 | type: array
1199 | items:
1200 | $ref: '#/definitions/Sticker'
1201 | description: Stickers
1202 | responses: {}
1203 | parameters: {}
1204 | securityDefinitions: {}
1205 | tags:
1206 | - name: Auth
1207 | description: Auth operations
1208 | - name: Chats
1209 | description: Chats operations
1210 | - name: Leaderboard
1211 | description: Leaderboard operations (prefix /game/api/v2)
1212 | - name: Oauth
1213 | description: Oauth service
1214 | - name: Users
1215 | description: Users operations
1216 | - name: Charts
1217 | description: Charts operations
1218 | - name: Videos
1219 | description: Videos operations
1220 | - name: Stickers
1221 | description: Stickers operations
1222 |
--------------------------------------------------------------------------------