kopia lustrzana https://github.com/nextcloud/social
Make uploading files work
Signed-off-by: Carl Schwan <carl@carlschwan.eu>pull/1469/head
rodzic
b423ac536c
commit
e037394a50
|
@ -124,18 +124,27 @@ class LocalController extends Controller {
|
||||||
*
|
*
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*/
|
*/
|
||||||
public function postCreate(array $data): DataResponse {
|
public function postCreate(string $content = '', $to = null, string $type = null, ?string $replyTo = null, $attachments = null, ?string $hashtags = null): DataResponse {
|
||||||
|
|
||||||
|
$content = $content ?? '';
|
||||||
|
$to = is_string($to) ? [$to] : $to;
|
||||||
|
$to = $to ?? [];
|
||||||
|
$replyTo = $replyTo ?? '';
|
||||||
|
$type = $type ?? Stream::TYPE_PUBLIC;
|
||||||
|
$hashtags = $hashtags === '' ? [] : $hashtags;
|
||||||
|
$hashtags = $hashtags ?? [];
|
||||||
|
$attachments = $attachments ?? [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$actor = $this->accountService->getActorFromUserId($this->userId);
|
$actor = $this->accountService->getActorFromUserId($this->userId);
|
||||||
|
|
||||||
$post = new Post($actor);
|
$post = new Post($actor);
|
||||||
$post->setContent($this->get('content', $data, ''));
|
$post->setContent($content);
|
||||||
$post->setReplyTo($this->get('replyTo', $data, ''));
|
$post->setReplyTo($replyTo);
|
||||||
$post->setTo($this->getArray('to', $data, []));
|
$post->setTo($to);
|
||||||
$post->addTo($this->get('to', $data, ''));
|
$post->setType($type);
|
||||||
$post->setType($this->get('type', $data, Stream::TYPE_PUBLIC));
|
$post->setHashtags($hashtags);
|
||||||
$post->setHashtags($this->getArray('hashtags', $data, []));
|
$post->setAttachments($attachments);
|
||||||
$post->setAttachments($this->getArray('attachments', $data, []));
|
|
||||||
|
|
||||||
$token = '';
|
$token = '';
|
||||||
$activity = $this->postService->createPost($post, $token);
|
$activity = $this->postService->createPost($post, $token);
|
||||||
|
@ -151,7 +160,6 @@ class LocalController extends Controller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get info about a post (limited to viewer rights).
|
* Get info about a post (limited to viewer rights).
|
||||||
*
|
*
|
||||||
|
|
|
@ -137,6 +137,24 @@ class CacheDocumentService {
|
||||||
$document->setResizedCopy($resized);
|
$document->setResizedCopy($resized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function saveFromTempToCache(Document $document, string $tmpPath) {
|
||||||
|
$mime = mime_content_type($tmpPath);
|
||||||
|
|
||||||
|
$this->filterMimeTypes($mime);
|
||||||
|
|
||||||
|
$document->setMediaType($mime);
|
||||||
|
$document->setMimeType($mime);
|
||||||
|
|
||||||
|
$file = fopen($tmpPath, 'r');
|
||||||
|
$content = fread($file, filesize($tmpPath));
|
||||||
|
|
||||||
|
$filename = $this->generateFileFromContent($content);
|
||||||
|
$document->setLocalCopy($filename);
|
||||||
|
$this->resizeImage($content);
|
||||||
|
$resized = $this->generateFileFromContent($content);
|
||||||
|
$document->setResizedCopy($resized);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
|
|
@ -53,34 +53,20 @@ use OCA\Social\Model\ActivityPub\Object\Note;
|
||||||
use OCA\Social\Model\Post;
|
use OCA\Social\Model\Post;
|
||||||
use OCP\Files\NotFoundException;
|
use OCP\Files\NotFoundException;
|
||||||
use OCP\Files\NotPermittedException;
|
use OCP\Files\NotPermittedException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
class PostService {
|
class PostService {
|
||||||
private StreamService $streamService;
|
private StreamService $streamService;
|
||||||
|
|
||||||
private AccountService $accountService;
|
private AccountService $accountService;
|
||||||
|
|
||||||
private ActivityService $activityService;
|
private ActivityService $activityService;
|
||||||
|
|
||||||
private CacheDocumentService $cacheDocumentService;
|
private CacheDocumentService $cacheDocumentService;
|
||||||
|
|
||||||
private ConfigService $configService;
|
private ConfigService $configService;
|
||||||
|
|
||||||
private MiscService $miscService;
|
private MiscService $miscService;
|
||||||
|
private LoggerInterface $logger;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PostService constructor.
|
|
||||||
*
|
|
||||||
* @param StreamService $streamService
|
|
||||||
* @param AccountService $accountService
|
|
||||||
* @param ActivityService $activityService
|
|
||||||
* @param CacheDocumentService $cacheDocumentService
|
|
||||||
* @param ConfigService $configService
|
|
||||||
* @param MiscService $miscService
|
|
||||||
*/
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
StreamService $streamService, AccountService $accountService, ActivityService $activityService,
|
StreamService $streamService, AccountService $accountService, ActivityService $activityService,
|
||||||
CacheDocumentService $cacheDocumentService, ConfigService $configService, MiscService $miscService
|
CacheDocumentService $cacheDocumentService, ConfigService $configService, MiscService $miscService, LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
$this->streamService = $streamService;
|
$this->streamService = $streamService;
|
||||||
$this->accountService = $accountService;
|
$this->accountService = $accountService;
|
||||||
|
@ -88,6 +74,7 @@ class PostService {
|
||||||
$this->cacheDocumentService = $cacheDocumentService;
|
$this->cacheDocumentService = $cacheDocumentService;
|
||||||
$this->configService = $configService;
|
$this->configService = $configService;
|
||||||
$this->miscService = $miscService;
|
$this->miscService = $miscService;
|
||||||
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,15 +129,45 @@ class PostService {
|
||||||
*/
|
*/
|
||||||
private function generateDocumentsFromAttachments(Note $note, Post $post) {
|
private function generateDocumentsFromAttachments(Note $note, Post $post) {
|
||||||
$documents = [];
|
$documents = [];
|
||||||
foreach ($post->getAttachments() as $attachment) {
|
\OC::$server->getLogger()->error(var_export($_FILES["attachments"], true));
|
||||||
|
if (is_array($_FILES["attachments"]["error"])) {
|
||||||
|
foreach ($_FILES["attachments"]["error"] as $key => $error) {
|
||||||
|
if ($error == UPLOAD_ERR_OK) {
|
||||||
|
try {
|
||||||
|
$document = $this->generateDocumentFromAttachment($note, $key);
|
||||||
|
|
||||||
|
$service = AP::$activityPub->getInterfaceForItem($document);
|
||||||
|
$service->save($document);
|
||||||
|
|
||||||
|
$documents[] = $document;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
$document = $this->generateDocumentFromAttachment($note, $attachment);
|
$tmp_name = $_FILES["attachments"]["tmp_name"];
|
||||||
|
$name = basename($_FILES["attachments"]["name"]);
|
||||||
|
$tmpFile = tmpfile();
|
||||||
|
$tmpPath = stream_get_meta_data($tmpFile)['uri'];
|
||||||
|
if (move_uploaded_file($tmp_name, $tmpPath)) {
|
||||||
|
$document = new Document();
|
||||||
|
$document->setUrlCloud($this->configService->getCloudUrl());
|
||||||
|
$document->generateUniqueId('/documents/local');
|
||||||
|
$document->setParentId($note->getId());
|
||||||
|
$document->setPublic(true);
|
||||||
|
|
||||||
|
$this->cacheDocumentService->saveFromTempToCache($document, $tmpPath);
|
||||||
|
}
|
||||||
|
|
||||||
$service = AP::$activityPub->getInterfaceForItem($document);
|
$service = AP::$activityPub->getInterfaceForItem($document);
|
||||||
$service->save($document);
|
$service->save($document);
|
||||||
|
|
||||||
$documents[] = $document;
|
$documents[] = $document;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error($e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$post->setDocuments($documents);
|
$post->setDocuments($documents);
|
||||||
|
@ -168,21 +185,21 @@ class PostService {
|
||||||
* @throws SocialAppConfigException
|
* @throws SocialAppConfigException
|
||||||
* @throws UrlCloudException
|
* @throws UrlCloudException
|
||||||
*/
|
*/
|
||||||
private function generateDocumentFromAttachment(Note $note, string $attachment): Document {
|
private function generateDocumentFromAttachment(Note $note, int $key): Document {
|
||||||
list(, $data) = explode(';', $attachment);
|
$tmp_name = $_FILES["attachments"]["tmp_name"][$key];
|
||||||
list(, $data) = explode(',', $data);
|
$name = basename($_FILES["attachments"]["name"][$key]);
|
||||||
$content = base64_decode($data);
|
$tmpFile = tmpfile();
|
||||||
|
$tmpPath = stream_get_meta_data($tmpFile)['uri'];
|
||||||
|
if (move_uploaded_file($tmp_name, $tmpPath)) {
|
||||||
|
$document = new Document();
|
||||||
|
$document->setUrlCloud($this->configService->getCloudUrl());
|
||||||
|
$document->generateUniqueId('/documents/local');
|
||||||
|
$document->setParentId($note->getId());
|
||||||
|
$document->setPublic(true);
|
||||||
|
|
||||||
$document = new Document();
|
$this->cacheDocumentService->saveFromTempToCache($document, $tmpPath);
|
||||||
$document->setUrlCloud($this->configService->getCloudUrl());
|
}
|
||||||
$document->generateUniqueId('/documents/local');
|
|
||||||
$document->setParentId($note->getId());
|
|
||||||
$document->setPublic(true);
|
|
||||||
|
|
||||||
$mime = '';
|
|
||||||
$this->cacheDocumentService->saveLocalUploadToCache($document, $content, $mime);
|
|
||||||
$document->setMediaType($mime);
|
|
||||||
$document->setMimeType($mime);
|
|
||||||
|
|
||||||
return $document;
|
return $document;
|
||||||
}
|
}
|
||||||
|
|
|
@ -458,19 +458,20 @@ export default {
|
||||||
let content = contentHtml.replace(/<(?!\/div)[^>]+>/gi, '').replace(/<\/div>/gi, '\n').trim()
|
let content = contentHtml.replace(/<(?!\/div)[^>]+>/gi, '').replace(/<\/div>/gi, '\n').trim()
|
||||||
content = he.decode(content)
|
content = he.decode(content)
|
||||||
|
|
||||||
let data = {
|
let formData = new FormData()
|
||||||
content: content,
|
formData.append('content', content)
|
||||||
to: to,
|
formData.append('to', to)
|
||||||
hashtags: hashtags,
|
formData.append('hashtags', hashtags)
|
||||||
type: this.type,
|
formData.append('type', this.type)
|
||||||
attachments: this.previewUrls.map(preview => preview.result), // TODO send the summary and other props too
|
for (const preview of this.previewUrls) {
|
||||||
|
// TODO send the summary and other props too
|
||||||
|
formData.append('attachments', preview.result)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.replyTo) {
|
if (this.replyTo) {
|
||||||
data.replyTo = this.replyTo.id
|
formData.append('replyTo', this.replyTo.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return data
|
return formData
|
||||||
},
|
},
|
||||||
keyup(event) {
|
keyup(event) {
|
||||||
if (event.shiftKey || event.ctrlKey) {
|
if (event.shiftKey || event.ctrlKey) {
|
||||||
|
@ -487,7 +488,7 @@ export default {
|
||||||
|
|
||||||
// Trick to validate last mention when the user directly clicks on the "post" button without validating it.
|
// Trick to validate last mention when the user directly clicks on the "post" button without validating it.
|
||||||
let regex = /@([-\w]+)$/
|
let regex = /@([-\w]+)$/
|
||||||
let lastMention = postData.content.match(regex)
|
let lastMention = postData.get('content').match(regex)
|
||||||
if (lastMention) {
|
if (lastMention) {
|
||||||
|
|
||||||
// Ask the server for matching accounts, and wait for the results
|
// Ask the server for matching accounts, and wait for the results
|
||||||
|
@ -495,13 +496,13 @@ export default {
|
||||||
|
|
||||||
// Validate the last mention only when it matches a single account
|
// Validate the last mention only when it matches a single account
|
||||||
if (result.data.result.accounts.length === 1) {
|
if (result.data.result.accounts.length === 1) {
|
||||||
postData.content = postData.content.replace(regex, '@' + result.data.result.accounts[0].account)
|
postData.set('content', postData.get('content').replace(regex, '@' + result.data.result.accounts[0].account))
|
||||||
postData.to.push(result.data.result.accounts[0].account)
|
postData.set('to', postData.get('to').push(result.data.result.accounts[0].account))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort if the post is a direct message and no valid mentions were found
|
// Abort if the post is a direct message and no valid mentions were found
|
||||||
// if (this.type === 'direct' && postData.to.length === 0) {
|
// if (this.type === 'direct' && postData.get('to').length === 0) {
|
||||||
// OC.Notification.showTemporary(t('social', 'Error while trying to post your message: Could not find any valid recipients.'), { type: 'error' })
|
// OC.Notification.showTemporary(t('social', 'Error while trying to post your message: Could not find any valid recipients.'), { type: 'error' })
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -144,17 +144,19 @@ const actions = {
|
||||||
context.commit('setTimelineType', 'account')
|
context.commit('setTimelineType', 'account')
|
||||||
context.commit('setAccount', account)
|
context.commit('setAccount', account)
|
||||||
},
|
},
|
||||||
post(context, post) {
|
async post(context, post) {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
axios.post(generateUrl('apps/social/api/v1/post'), { data: post }).then((response) => {
|
const { data } = axios.post(generateUrl('apps/social/api/v1/post'), post, {
|
||||||
Logger.info('Post created with token ' + response.data.result.token)
|
headers: {
|
||||||
resolve(response)
|
'Content-Type': 'multipart/form-data'
|
||||||
}).catch((error) => {
|
}
|
||||||
OC.Notification.showTemporary('Failed to create a post')
|
|
||||||
Logger.error('Failed to create a post', { 'error': error.response })
|
|
||||||
reject(error)
|
|
||||||
})
|
})
|
||||||
})
|
Logger.info('Post created with token ' + data.result.token)
|
||||||
|
} catch (error) {
|
||||||
|
OC.Notification.showTemporary('Failed to create a post')
|
||||||
|
console.error(error)
|
||||||
|
Logger.error('Failed to create a post', { 'error': error.response })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
postDelete(context, post) {
|
postDelete(context, post) {
|
||||||
return axios.delete(generateUrl(`apps/social/api/v1/post?id=${post.id}`)).then((response) => {
|
return axios.delete(generateUrl(`apps/social/api/v1/post?id=${post.id}`)).then((response) => {
|
||||||
|
|
Ładowanie…
Reference in New Issue