Skip to content

Commit

Permalink
Возможность выбрать группу куда загружать видос
Browse files Browse the repository at this point in the history
  • Loading branch information
Spliterash committed Oct 17, 2024
1 parent 0a21841 commit 4a4cfd9
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 11 deletions.
16 changes: 16 additions & 0 deletions front/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^22.7.6",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
Expand Down
8 changes: 5 additions & 3 deletions front/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import {ScreenSpinner, SplitCol, SplitLayout} from '@vkontakte/vkui';
import {Home} from './panels';
import {APP_ID, HashInput} from "./consts.ts";
import Denied from "./panels/Denied.tsx";
import bridge, {ReceiveData} from "@vkontakte/vk-bridge";
import bridge, {ReceiveData, UserInfo} from "@vkontakte/vk-bridge";
// Поебать
const hash: HashInput = JSON.parse(decodeURI(window.location.hash.substring(1)))

export const App = () => {
const [token, setToken] = useState<string | null>(null)
const [popout, setPopout] = useState<ReactNode | null>(<ScreenSpinner size="large"/>);
const [user, setUser] = useState<UserInfo | null>(null)
const [denied, setDenied] = useState(false)

async function fetchData() {
await askPermissions()
setUser(await bridge.send('VKWebAppGetUserInfo'))
setPopout(null)
}

Expand Down Expand Up @@ -48,8 +50,8 @@ export const App = () => {
function component() {
if (denied)
return <Denied onRetry={askPermissions}/>
else if (popout == null)
return <Home id={hash.id} token={token ?? ""} video={hash.video}/>
else if (popout == null && user != null)
return <Home id={hash.id} token={token ?? ""} video={hash.video} user={user}/>
else
return <div/>
}
Expand Down
5 changes: 4 additions & 1 deletion front/src/consts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import bridge from "@vkontakte/vk-bridge";

export const APP_ID = 52483593
export const VK_API_VERSION = "5.199"

export interface HashInput {
id: string
Expand All @@ -16,10 +17,12 @@ export interface VideoInfo {
export interface VideoSaveRequest {
// ID запроса в моей системе
id: string
userId: number
groupId?: number
// Куда перелить
uploadUrl: string
}

export function closeApp(){
export function closeApp() {
bridge.send("VKWebAppClose")
}
95 changes: 95 additions & 0 deletions front/src/panels/GroupSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import bridge, {GroupInfo, UserInfo} from "@vkontakte/vk-bridge";
import {VK_API_VERSION} from "../consts.ts";
import {ChangeEvent, useState} from "react";
import {Avatar, CustomSelectOption, FormItem, Select} from "@vkontakte/vkui";
import {CustomSelectOptionInterface} from "@vkontakte/vkui/src/components/CustomSelect/CustomSelect.tsx";


export interface GroupSelectProps {
token: string,
user: UserInfo,
setValue: (current: GroupInfo | null) => void
}

const User: CustomSelectOptionInterface = {
value: "user",
label: "Свой аккаунт",
}

interface Group extends CustomSelectOptionInterface {
group: GroupInfo
}

type Row = typeof User | Group

export default function GroupSelect({token, setValue, user}: GroupSelectProps) {
const [nativeValue, setNativeValue] = useState<string>("user")
const [listOptions, setListOptions] = useState<Row[]>([User])
const [loading, setLoading] = useState(false)

async function checkGroups() {
if (loading) return
if (listOptions.length > 1) return
setLoading(true)
try {
const result = await bridge.send("VKWebAppCallAPIMethod", {
method: "groups.get",
params: {
access_token: token,
v: VK_API_VERSION,
filter: "admin,editor",
extended: 1
}
})
const groups = result.response.items as GroupInfo[]
const newList: Row[] = groups.map(function (g: GroupInfo): Group {
return {
value: g.id,
label: g.name,
group: g
}
})
newList.unshift(User)

setListOptions(newList)
} finally {
setLoading(false)
}
}

function handleChange(event: ChangeEvent<HTMLSelectElement>) {
const value = event.target.value;
setNativeValue(event.target.value)

const select = listOptions.find(e => e.value == value)

if (!select) return
else if (select == User) setValue(null)
else setValue(select.group)
}

function getAvatar(option: Row): string {
if (option == User) return user.photo_100
else return option.group.photo_100
}

return <FormItem
top="Сохранить в"
bottom="Выберите куда видео будет сохраненно"
onClick={checkGroups}
>
<Select
fetching={loading}
value={nativeValue}
options={listOptions}
onOpen={checkGroups}
onChange={handleChange}
renderOption={({option, ...restProps}) => (
<CustomSelectOption
{...restProps}
key={option.value as string}
before={<Avatar size={24} src={getAvatar(option)}/>}
/>)}
/>
</FormItem>
}
16 changes: 12 additions & 4 deletions front/src/panels/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ import {
SimpleCell,
Textarea
} from '@vkontakte/vkui';
import {VideoInfo, VideoSaveRequest} from "../consts.ts";
import {VideoInfo, VideoSaveRequest, VK_API_VERSION} from "../consts.ts";
import axios, {AxiosError} from "axios";
import bridge from "@vkontakte/vk-bridge";
import bridge, {GroupInfo, UserInfo} from "@vkontakte/vk-bridge";
import Success from "./Success.tsx";
import Error from "./Error.tsx";
import GroupSelect from "./GroupSelect.tsx";

const ENDPOINT = import.meta.env.VITE_APP_HOST + "/videos/save"

export interface HomeProps extends NavIdProps {
id: string,

user: UserInfo,
video: VideoInfo
token: string
}
Expand All @@ -33,21 +35,26 @@ export const Home: FC<HomeProps> = (props) => {
const [error, setError] = useState<string | null>(null)
const [videoTitle, setVideoTitle] = useState(props.video.name)
const [videoDescription, setVideoDescription] = useState("Загружено через @unlock_video")
const [group, setGroup] = useState<GroupInfo | null>(null)

async function save() {
if (clicked) return
setClicked(true)
const response = await bridge.send("VKWebAppCallAPIMethod", {
method: "video.save", params: {
access_token: props.token,
v: "5.199",
v: VK_API_VERSION,
name: videoTitle,
description: videoDescription
description: videoDescription,
// @ts-expect-error я манал ещё проперти эту обрабатывать, мне тупо впадлу
group_id: group?.id
}
})
const url = response.response["upload_url"]
const request: VideoSaveRequest = {
id: props.id,
userId: props.user.id,
groupId: group?.id,
uploadUrl: url,
}
try {
Expand Down Expand Up @@ -83,6 +90,7 @@ export const Home: FC<HomeProps> = (props) => {
<FormItem top="Описание">
<Textarea value={videoDescription} onChange={e => setVideoDescription(e.target.value)}/>
</FormItem>
<GroupSelect user={props.user} token={props.token} setValue={setGroup}/>
<FormItem>
<Button type="submit" size="l" stretched disabled={clicked}>
Сохранить
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class VideoController(

@Post(Routes.SAVE)
suspend fun save(@Body request: VideoSaveRequest): Boolean {
videoSaveService.processUrl(request.id, request.uploadUrl)
videoSaveService.processUrl(request)

return true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ import java.util.*

data class VideoSaveRequest(
val id: UUID,
val userId: Long,
val groupId: Long?,
val uploadUrl: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ru.spliterash.vkVideoUnlocker.common.InputStreamSource
import ru.spliterash.vkVideoUnlocker.longpoll.message.RootMessage
import ru.spliterash.vkVideoUnlocker.message.editableMessage.EditableMessage
import ru.spliterash.vkVideoUnlocker.video.api.VideosCommons
import ru.spliterash.vkVideoUnlocker.video.controller.request.VideoSaveRequest
import ru.spliterash.vkVideoUnlocker.video.exceptions.VideoSaveExpireException
import ru.spliterash.vkVideoUnlocker.video.service.dto.VideoSaveEntry
import java.util.*
Expand Down Expand Up @@ -42,7 +43,8 @@ class VideoSaveService(
return entry
}

suspend fun processUrl(id: UUID, uploadUrl: String) {
suspend fun processUrl(input: VideoSaveRequest) {
val (id, userId, groupId, uploadUrl) = input
val entry = pending.remove(id) ?: throw VideoSaveExpireException()
scope.launch {
val editMessageTask = launch {
Expand All @@ -51,7 +53,8 @@ class VideoSaveService(
}
try {
val savedId = commons.upload(uploadUrl, entry.accessor)
entry.message.sendOrUpdate("Успешно", "video${entry.userId}_$savedId")
val ownerId = if (groupId == null) userId else -groupId
entry.message.sendOrUpdate("Успешно", "video${ownerId}_${savedId}")
} catch (ex: Exception) {
entry.message.sendOrUpdate("Ошибка при загрузке(${ex.javaClass.simpleName}): ${ex.localizedMessage}")
} finally {
Expand Down

0 comments on commit 4a4cfd9

Please sign in to comment.