mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-07 16:37:02 +03:00
Draft code to share Nextcloud files as links #569
This commit is contained in:
parent
14bd9720e9
commit
6c276b9b03
3 changed files with 144 additions and 52 deletions
|
|
@ -160,7 +160,7 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
if (!$bAdmin && \is_array($aResult)) {
|
if (!$bAdmin && \is_array($aResult)) {
|
||||||
$sUID = \OC::$server->getUserSession()->getUser()->getUID();
|
$sUID = \OC::$server->getUserSession()->getUser()->getUID();
|
||||||
$sWebDAV = \OC::$server->getURLGenerator()->linkTo('', 'remote.php') . '/dav/';
|
$sWebDAV = \OC::$server->getURLGenerator()->linkTo('', 'remote.php') . '/dav';
|
||||||
// $sWebDAV = \OCP\Util::linkToRemote('dav');
|
// $sWebDAV = \OCP\Util::linkToRemote('dav');
|
||||||
$aResult['Nextcloud'] = [
|
$aResult['Nextcloud'] = [
|
||||||
'UID' => $sUID,
|
'UID' => $sUID,
|
||||||
|
|
|
||||||
|
|
@ -7,33 +7,30 @@
|
||||||
view.nextcloudAttach = () => {
|
view.nextcloudAttach = () => {
|
||||||
rl.nextcloud.selectFiles().then(files => {
|
rl.nextcloud.selectFiles().then(files => {
|
||||||
files && files.forEach(file => {
|
files && files.forEach(file => {
|
||||||
let attachment = view.addAttachmentHelper(
|
if (file.name) {
|
||||||
Jua?.randomId(),
|
let attachment = view.addAttachmentHelper(
|
||||||
file.name.replace(/^.*\/([^/]+)$/, '$1'),
|
Jua?.randomId(),
|
||||||
file.size
|
file.name.replace(/^.*\/([^/]+)$/, '$1'),
|
||||||
);
|
file.size
|
||||||
attachment
|
);
|
||||||
.waiting(false)
|
|
||||||
.uploading(true)
|
|
||||||
.complete(false);
|
|
||||||
|
|
||||||
rl.pluginRemoteRequest(
|
rl.pluginRemoteRequest(
|
||||||
(iError, data) => {
|
(iError, data) => {
|
||||||
attachment
|
attachment.uploading(false).complete(true);
|
||||||
.uploading(false)
|
if (iError) {
|
||||||
.complete(true);
|
attachment.error(data?.Result?.error || 'failed');
|
||||||
if (iError) {
|
} else {
|
||||||
attachment.error(data?.Result?.error || 'failed');
|
attachment.tempName(data.Result.tempName);
|
||||||
} else {
|
}
|
||||||
attachment.tempName(data.Result.tempName);
|
},
|
||||||
|
'NextcloudAttachFile',
|
||||||
|
{
|
||||||
|
'file': file.name
|
||||||
}
|
}
|
||||||
},
|
);
|
||||||
'NextcloudAttachFile',
|
} else if (file.url) {
|
||||||
{
|
view.oEditor.editor.squire.makeLink(file.url);
|
||||||
'file': file.name
|
}
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,77 @@
|
||||||
(rl => {
|
(rl => {
|
||||||
|
|
||||||
const
|
const
|
||||||
namespace = 'DAV:',
|
nsDAV = 'DAV:',
|
||||||
|
nsNC = 'http://nextcloud.org/ns',
|
||||||
|
nsOC = 'http://owncloud.org/ns',
|
||||||
|
nsOCS = 'http://open-collaboration-services.org/ns',
|
||||||
nsCalDAV = 'urn:ietf:params:xml:ns:caldav',
|
nsCalDAV = 'urn:ietf:params:xml:ns:caldav',
|
||||||
|
|
||||||
|
OC = () => parent.OC,
|
||||||
|
|
||||||
|
// Nextcloud 19 deprecated generateUrl, but screw `import { generateUrl } from "@nextcloud/router"`
|
||||||
|
generateUrl = path => OC().webroot + (OC().config.modRewriteWorking ? '' : '/index.php') + path,
|
||||||
|
generateRemoteUrl = path => location.protocol + '//' + location.host + generateUrl(path),
|
||||||
|
|
||||||
|
// shareTypes = {0 = user, 1 = group, 3 = public link}
|
||||||
|
|
||||||
propfindFiles = `<?xml version="1.0"?>
|
propfindFiles = `<?xml version="1.0"?>
|
||||||
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
|
<propfind xmlns="DAV:" xmlns:oc="${nsOC}" xmlns:ocs="${nsOCS}" xmlns:nc="${nsNC}">
|
||||||
<d:prop>
|
<prop>
|
||||||
<d:resourcetype/>
|
<oc:fileid/>
|
||||||
<oc:size/>
|
<oc:size/>
|
||||||
<d:getcontentlength/>
|
<resourcetype/>
|
||||||
</d:prop>
|
<getcontentlength/>
|
||||||
</d:propfind>`,
|
|
||||||
|
<getcontenttype/>
|
||||||
|
<oc:permissions/>
|
||||||
|
<ocs:share-permissions/>
|
||||||
|
<nc:share-attributes/>
|
||||||
|
<oc:share-types/>
|
||||||
|
<nc:is-encrypted/>
|
||||||
|
</prop>
|
||||||
|
</propfind>`,
|
||||||
|
/*
|
||||||
|
<d:propstat>
|
||||||
|
<d:prop>
|
||||||
|
<d:getcontenttype>video/mp4</d:getcontenttype>
|
||||||
|
<oc:permissions>RGDNVW</oc:permissions>
|
||||||
|
<d:getcontentlength>3963036</d:getcontentlength>
|
||||||
|
<ocs:share-permissions>19</ocs:share-permissions>
|
||||||
|
<nc:share-attributes>[]</nc:share-attributes>
|
||||||
|
<oc:share-types>
|
||||||
|
<oc:share-type>3</oc:share-type>
|
||||||
|
</oc:share-types>
|
||||||
|
</d:prop>
|
||||||
|
<d:status>HTTP/1.1 200 OK</d:status>
|
||||||
|
</d:propstat>
|
||||||
|
<d:propstat>
|
||||||
|
<d:prop>
|
||||||
|
<nc:is-encrypted/>
|
||||||
|
</d:prop>
|
||||||
|
<d:status>HTTP/1.1 404 Not Found</d:status>
|
||||||
|
</d:propstat>
|
||||||
|
*/
|
||||||
|
|
||||||
propfindCal = `<?xml version="1.0"?>
|
propfindCal = `<?xml version="1.0"?>
|
||||||
<d:propfind xmlns:d="DAV:">
|
<propfind xmlns="DAV:">
|
||||||
<d:prop>
|
<prop>
|
||||||
<d:resourcetype/>
|
<resourcetype/>
|
||||||
<d:current-user-privilege-set/>
|
<current-user-privilege-set/>
|
||||||
<d:displayname/>
|
<displayname/>
|
||||||
</d:prop>
|
</prop>
|
||||||
</d:propfind>`,
|
</propfind>`,
|
||||||
|
|
||||||
xmlParser = new DOMParser(),
|
xmlParser = new DOMParser(),
|
||||||
pathRegex = /.*\/remote.php\/dav\/[^/]+\/[^/]+/g,
|
pathRegex = /.*\/remote.php\/dav\/[^/]+\/[^/]+/g,
|
||||||
|
|
||||||
getDavElementsByTagName = (parent, localName) => parent.getElementsByTagNameNS(namespace, localName),
|
getElementsByTagName = (parent, namespace, localName) => parent.getElementsByTagNameNS(namespace, localName),
|
||||||
|
getDavElementsByTagName = (parent, localName) => getElementsByTagName(parent, nsDAV, localName),
|
||||||
getDavElementByTagName = (parent, localName) => getDavElementsByTagName(parent, localName)?.item(0),
|
getDavElementByTagName = (parent, localName) => getDavElementsByTagName(parent, localName)?.item(0),
|
||||||
getElementByTagName = (parent, localName) => +parent.getElementsByTagName(localName)?.item(0),
|
getElementByTagName = (parent, localName) => +parent.getElementsByTagName(localName)?.item(0),
|
||||||
|
|
||||||
davFetch = (mode, path, options) => {
|
davFetch = (mode, path, options) => {
|
||||||
if (!parent.OC.requestToken) {
|
if (!OC().requestToken) {
|
||||||
return Promise.reject(new Error('OC.requestToken missing'));
|
return Promise.reject(new Error('OC.requestToken missing'));
|
||||||
}
|
}
|
||||||
let cfg = rl.settings.get('Nextcloud');
|
let cfg = rl.settings.get('Nextcloud');
|
||||||
|
|
@ -41,7 +82,7 @@ const
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
headers: {}
|
headers: {}
|
||||||
}, options);
|
}, options);
|
||||||
options.headers.requesttoken = parent.OC.requestToken;
|
options.headers.requesttoken = OC().requestToken;
|
||||||
// cfg.UID = document.head.dataset.user
|
// cfg.UID = document.head.dataset.user
|
||||||
return fetch(cfg.WebDAV + '/' + mode + '/' + cfg.UID + path, options);
|
return fetch(cfg.WebDAV + '/' + mode + '/' + cfg.UID + path, options);
|
||||||
},
|
},
|
||||||
|
|
@ -51,7 +92,7 @@ const
|
||||||
createDirectory = path => davFetchFiles(path, { method: 'MKCOL' }),
|
createDirectory = path => davFetchFiles(path, { method: 'MKCOL' }),
|
||||||
|
|
||||||
fetchFiles = path => {
|
fetchFiles = path => {
|
||||||
if (!parent.OC.requestToken) {
|
if (!OC().requestToken) {
|
||||||
return Promise.reject(new Error('OC.requestToken missing'));
|
return Promise.reject(new Error('OC.requestToken missing'));
|
||||||
}
|
}
|
||||||
return davFetchFiles(path, {
|
return davFetchFiles(path, {
|
||||||
|
|
@ -85,6 +126,7 @@ const
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
elem.isFile = true;
|
elem.isFile = true;
|
||||||
|
elem.id = e.getElementsByTagNameNS(nsOC, 'fileid')?.item(0)?.textContent;
|
||||||
elem.size = getDavElementByTagName(e, 'getcontentlength')?.textContent
|
elem.size = getDavElementByTagName(e, 'getcontentlength')?.textContent
|
||||||
|| getElementByTagName(e, 'oc:size')?.textContent;
|
|| getElementByTagName(e, 'oc:size')?.textContent;
|
||||||
}
|
}
|
||||||
|
|
@ -110,12 +152,12 @@ const
|
||||||
summary.dataset.icon = '📁';
|
summary.dataset.icon = '📁';
|
||||||
if (!view.files()) {
|
if (!view.files()) {
|
||||||
let btn = document.createElement('button');
|
let btn = document.createElement('button');
|
||||||
btn.item_name = item.name;
|
|
||||||
btn.name = 'select';
|
btn.name = 'select';
|
||||||
btn.textContent = 'select';
|
btn.textContent = 'select';
|
||||||
btn.className = 'button-vue';
|
btn.className = 'button-vue';
|
||||||
btn.style.marginLeft = '1em';
|
btn.style.marginLeft = '1em';
|
||||||
summary.append(btn);
|
summary.append(btn);
|
||||||
|
summary.item_name = item.name;
|
||||||
}
|
}
|
||||||
details.append(summary);
|
details.append(summary);
|
||||||
details.append(ul);
|
details.append(ul);
|
||||||
|
|
@ -127,17 +169,33 @@ const
|
||||||
if (view.files()) {
|
if (view.files()) {
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
if (item.isFile) {
|
if (item.isFile) {
|
||||||
// TODO show files
|
|
||||||
let li = document.createElement('li'),
|
let li = document.createElement('li'),
|
||||||
btn = document.createElement('button');
|
btn = document.createElement('button');
|
||||||
btn.item = item;
|
|
||||||
|
li.item = item;
|
||||||
|
li.textContent = item.name.replace(/^.*\/([^/]+)$/, '$1');
|
||||||
|
li.dataset.icon = '🗎';
|
||||||
|
|
||||||
btn.name = 'select';
|
btn.name = 'select';
|
||||||
btn.textContent = 'select';
|
btn.textContent = 'select';
|
||||||
btn.className = 'button-vue';
|
btn.className = 'button-vue';
|
||||||
btn.style.marginLeft = '1em';
|
btn.style.marginLeft = '1em';
|
||||||
li.textContent = item.name.replace(/^.*\/([^/]+)$/, '$1');
|
|
||||||
li.dataset.icon = '🗎';
|
|
||||||
li.append(btn);
|
li.append(btn);
|
||||||
|
|
||||||
|
btn = document.createElement('button');
|
||||||
|
btn.name = 'share-internal';
|
||||||
|
btn.textContent = '🔗 internal';
|
||||||
|
btn.className = 'button-vue';
|
||||||
|
btn.style.marginLeft = '1em';
|
||||||
|
li.append(btn);
|
||||||
|
/*
|
||||||
|
btn = document.createElement('button');
|
||||||
|
btn.name = 'share-public';
|
||||||
|
btn.textContent = '🔗 public';
|
||||||
|
btn.className = 'button-vue';
|
||||||
|
btn.style.marginLeft = '1em';
|
||||||
|
li.append(btn);
|
||||||
|
*/
|
||||||
parent.append(li);
|
parent.append(li);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -150,8 +208,8 @@ const
|
||||||
btn.name = 'create';
|
btn.name = 'create';
|
||||||
btn.textContent = 'create & select';
|
btn.textContent = 'create & select';
|
||||||
btn.className = 'button-vue';
|
btn.className = 'button-vue';
|
||||||
btn.item_name = path;
|
|
||||||
btn.input = input;
|
btn.input = input;
|
||||||
|
li.item_path = path;
|
||||||
li.append(input);
|
li.append(input);
|
||||||
li.append(btn);
|
li.append(btn);
|
||||||
parent.append(li);
|
parent.append(li);
|
||||||
|
|
@ -171,13 +229,50 @@ class NextcloudFilesPopupView extends rl.pluginPopupView {
|
||||||
this.tree.addEventListener('click', event => {
|
this.tree.addEventListener('click', event => {
|
||||||
let el = event.target;
|
let el = event.target;
|
||||||
if (el.matches('button')) {
|
if (el.matches('button')) {
|
||||||
|
let parent = el.parentNode;
|
||||||
if ('select' == el.name) {
|
if ('select' == el.name) {
|
||||||
this.select = this.files() ? [el.item] : el.item_name;
|
this.select = this.files() ? [parent.item] : parent.item_name;
|
||||||
this.close();
|
this.close();
|
||||||
|
} else if ('share-internal' == el.name) {
|
||||||
|
this.select = [{url:generateRemoteUrl(`/f/${parent.item.id}`)}];
|
||||||
|
this.close();
|
||||||
|
} else if ('share-public' == el.name) {
|
||||||
|
/*
|
||||||
|
if (3 == share-type) {
|
||||||
|
GET generateUrl(`/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json&path=${encodeURIComponent(parent.item.name)}&reshares=true`);
|
||||||
|
} else {
|
||||||
|
POST generateUrl(`/ocs/v2.php/apps/files_sharing/api/v1/shares`)
|
||||||
|
> {"path":"/Nextcloud intro.mp4","shareType":3,"attributes":"[]"}
|
||||||
|
< {"ocs":{"meta":{"status":"ok","statuscode":200,"message":"OK"},
|
||||||
|
"data":{
|
||||||
|
"id":"2",
|
||||||
|
"share_type":3,
|
||||||
|
"permissions":17,
|
||||||
|
"token":"7GK9mL9LCTseSgK",
|
||||||
|
"path":"\/Nextcloud intro.mp4",
|
||||||
|
"item_type":"file",
|
||||||
|
"mimetype":"video\/mp4",
|
||||||
|
"storage":1,
|
||||||
|
"item_source":20,
|
||||||
|
"file_source":20,
|
||||||
|
"file_parent":2,
|
||||||
|
"file_target":"\/Nextcloud intro.mp4",
|
||||||
|
"password":null,
|
||||||
|
"url":"https:\/\/example.com\/index.php\/s\/7GK9mL9LCTseSgK",
|
||||||
|
"mail_send":1,
|
||||||
|
"hide_download":0,
|
||||||
|
"attributes":null
|
||||||
|
}}}
|
||||||
|
GET /index.php/s/7GK9mL9LCTseSgK
|
||||||
|
PUT /ocs/v2.php/apps/files_sharing/api/v1/shares/2
|
||||||
|
> {"expireDate":"\"2022-11-29T23:00:00.000Z\""}
|
||||||
|
> {"password":"ABC09"}
|
||||||
|
}
|
||||||
|
*/
|
||||||
} else if ('create' == el.name) {
|
} else if ('create' == el.name) {
|
||||||
let name = el.input.value.replace(/[|\\?*<":>+[]\/&\s]/g, '');
|
let name = el.input.value.replace(/[|\\?*<":>+[]\/&\s]/g, '');
|
||||||
if (name.length) {
|
if (name.length) {
|
||||||
name = el.item_name + '/' + name;
|
name = parent.item_path + '/' + name;
|
||||||
createDirectory(name).then(response => {
|
createDirectory(name).then(response => {
|
||||||
if (response.status == 201) {
|
if (response.status == 201) {
|
||||||
this.select = name;
|
this.select = name;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue