-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathshareVkPost.ts
181 lines (162 loc) · 7.48 KB
/
shareVkPost.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import { api } from '@ktsstudio/mediaproject-utils';
import bridge, { ErrorData } from '@vkontakte/vk-bridge';
import { callVkApi } from './callVkApi';
import { checkVkUserDenied } from './checkVkUserDenied';
import {
UploadFromApiToVkResponseType,
ShareVkPostResponseType,
ShareVkPostWithUploadParamsType,
ShareVkPostWithUploadResponseType,
ShareVkPostPropsType,
SaveVkWallPhotoResponseType,
} from './types';
/**
* Утилита для шеринга поста на стену.
*
* @param {ShareVkPostPropsType} props - Объект параметров, передаваемый в метод VKWebAppShowWallPostBox. Так же может принимать поля link_image, link_button и link_title, необходимые для шеринга в сниппет.
* @returns {Promise<ShareVkPostResponseType | void>} Возвращает ответ, полученный на запрос VKWebAppShowWallPostBox с переданными параметрами.
*
* @see {@link https://dev.vk.com/bridge/VKWebAppShowWallPostBox}
*/
const shareVkPost = async (
props: ShareVkPostPropsType
): Promise<ShareVkPostResponseType | void> => {
try {
return await bridge.send('VKWebAppShowWallPostBox', props);
} catch (error) {
const errorData = error as ErrorData;
if (checkVkUserDenied(errorData)) {
return undefined;
}
return errorData;
}
};
/**
* Утилита для шеринга поста на стену с загрузкой картинки в альбом стены пользователя.
*
* 1. Получает URL сервера ВКонтакте.
*
* 2. Передает полученный URL и файл картинки бэкенду KTS, который загружает картинку
* на сервер ВКонтакте и возвращает ссылку на нее, а так же данные сервера.
*
* 3. Сохраняет загруженную на сервер ВКонтакте картинку в альбом стены пользователя.
*
* 4. Вызывает окно шеринга поста, где во вложениях будет загруженная в альбом картинка.
*
* @param {ShareVkPostWithUploadParamsType} props Параметры для шеринга поста с загрузкой картинки в альбом.
* @param {ShareVkPostPropsType} props.postProps Параметры для шеринга поста, передаваемые в {@link shareVkPost}.
* @param {File} props.file Картинка (в виде файла), которую нужно загрузить.
* @param {UrlConfigType} props.apiUploadUrl Endpoint бэкенда KTS, на который нужно отправить запрос для загрузки картинки на сервер ВКонтакте.
* @param {number} props.userId ID пользователя, на стену к которому нужно загрузить картинку и пошерить пост.
* @param {number} props.appId ID текущего приложения.
* @param {string} props.accessToken Токен доступа для обращения к API ВКонтакте (передается в {@link callVkApi}). По умолчанию берется из window.access_token.
* @param {VoidFunction} props.onUserDeniedAccess Коллбэк, вызываемый в случае, если пользователь не дал разрешение на получение прав доступа внутри {@link callVkApi}.
* @param {VoidFunction} props.onErrorOccurred Коллбэк, вызываемый в случае, если произошла ошибка.
* @returns {Promise<ShareVkPostWithUploadResponseType | void>} Возвращает ответ, полученный на запрос VKWebAppShowWallPostBox или VKWebAppCallAPIMethod с переданными параметрами.
*
* @see {@link https://dev.vk.com/api/upload} (см. раздел "Загрузка фотографии на стену")
*/
const shareVkPostWithUpload = async ({
postProps,
file,
apiUploadUrl,
userId,
appId,
accessToken = window.access_token,
onUserDeniedAccess,
onErrorOccurred,
}: ShareVkPostWithUploadParamsType): Promise<ShareVkPostWithUploadResponseType | void> => {
try {
/**
* Получаем URL сервера для загрузки фото
*/
const getWallUploadServerData = await callVkApi({
method: 'photos.getWallUploadServer',
accessToken,
getAccessTokenParams: {
appId,
scopes: ['photos'],
onUserDeniedAll: onUserDeniedAccess,
onUserDeniedSomeScopes: onUserDeniedAccess,
},
renewTokenIfExpired: true,
});
if (getWallUploadServerData.error_type) {
onErrorOccurred?.(getWallUploadServerData);
return getWallUploadServerData;
}
/**
* Получили ссылку на сервер загрузки,
* теперь отправляем картинку на бэк для загрузки
*/
const {
response: apiUploadResponse,
error,
errorData,
}: UploadFromApiToVkResponseType = await api(
apiUploadUrl,
{
image: file,
server_url: getWallUploadServerData.response.upload_url,
},
{},
true
);
/**
* Если загрузить картинку на сервер не получилось,
* обрабатываем ошибку и дальше не идем
*/
if (!apiUploadResponse || error) {
onErrorOccurred?.(error, errorData);
return;
}
const { hash, photo, server } = apiUploadResponse; // получили картинку, id сервера и хэш
/**
* Сохраняем фото к пользователю,
* передавая все поученное на предыдущем шаге
* в метод сохранения картинки в альбоме стены
*/
const saveWallPhotoData: SaveVkWallPhotoResponseType = await callVkApi({
method: 'photos.saveWallPhoto',
accessToken,
/**
* Здесь устанавливаем false, чтобы запрос доступа не показывался дважды
* (в начале этой функции уже есть запрос)
*/
renewTokenIfExpired: false,
params: {
hash,
photo,
server: Number(server),
user_id: userId,
},
getAccessTokenParams: { appId },
});
if (saveWallPhotoData.error_type || !saveWallPhotoData.response?.[0]) {
onErrorOccurred?.(saveWallPhotoData);
return;
}
/**
* Получили id загруженной картинки и id пользователя
*/
// eslint-disable-next-line prefer-destructuring
const { id: mediaId, owner_id: ownerId } = saveWallPhotoData.response[0];
const uploadedPhotoAttachment = `photo${ownerId}_${mediaId}`;
/**
* На этом моменте вылетает предложение зашерить пост
*/
return await shareVkPost({
...postProps,
attachments: postProps.attachments
? postProps.attachments.concat(`,${uploadedPhotoAttachment}`)
: uploadedPhotoAttachment,
});
} catch (error) {
const errorData = error as ErrorData;
if (!checkVkUserDenied(errorData)) {
onErrorOccurred?.(errorData);
}
return errorData;
}
};
export { shareVkPost, shareVkPostWithUpload };