基于 Nextcloud 的二次开发

Nextcloud 是个不错的网盘系统,开源免费,支持 Windows Ad 域,而且开放了很多接口可以用于二次开发。

最近基于 Nextcloud 做了几个二次开发的功能,下面介绍一下过程。

第一个需求是和公司业务系统对接起来,实现建立项目时自动为项目负责人建立一个同名文件夹和子文件夹。
第二个需求是开放一个页面,可以浏览项目文件夹里的子文件夹、文件等。
第三个需求是可以在开放页面下载列出的文件。

先看第一个需求,我需要做一个接口给业务系统,入参为项目名称的人员唯一信息和项目名称。
Nextcloud 有现成的建立文件夹方法,预想会很顺利。但还是遇到了问题。
由于公司使用的 Windows Ad 域,我是获取不到项目负责人的密码的,所以不能使用项目负责人的帐号去建立文件夹。
然后灵光一闪,我可以使用一个固定的帐号(如:新建个帐户 Administrator)去建立这个文件夹,然后把这个文件夹分享给项目负责人,并分配一定的权限。
但是在找人的步骤又遇到了困难,因为没有表存域帐号。翻来翻去,在 oc_accounts 表里找到了邮箱信息,员工的邮箱基本上都是唯一的,所以可以用这个。
第一个需求方案差不多了,部份(伪)代码如下:

var sql = $"select * from oc_accounts where data like '%\"{email}\"%'"; //查找要分享的用户
oc_accounts[] rst = conn.Query(sql).ToArray();
if(l.Length < 1)
    return (false, null, $"网盘没有找到您提供的域帐号或邮箱"); //没找到要分享的人,直接返回错误
if(l.Length > 1)
    return (false, null, $"网盘找到了多个用户,请确认您提供的邮箱地址正确!");//找到多个也不行
var cre = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Adminitrator}:{密码}"));//固定帐号的登录名和密码
(result, header, statusCode) = ExtMethods.ProcessRequest(null, $"{网盘域名}/remote.php/dav/files/{Administrator的根目录(可在oc_ldap_user_mapping表查询)}/{folderName}", new Dictionary<string, string>() { { "Authorization", $"Basic {cre}" } }, "MKCOL", null, null);//这个是 Nextcloud 提供的接口,用来建立文件夹。

上边是建立文件夹,然后是分享部分:

var url = $"{网盘域名}/ocs/v2.php/apps/files_sharing/api/v1/shares";//接口地址
var inputHeader = new Dictionary<string, string>() { { "OCS-APIRequest", "true" }, { "Authorization", $"Basic {cre}" }, { "Content-Type", $"multipart/form-data; } };
string body = $"shareType=0&shareWith={shareWith}&permissions=31&path={path}";
//shareWith 是要分享的人,permissions 是权限,31是最大权限;path 是要分享的路径
(result, header, statusCode) = ExtMethods.ProcessRequest(System.Text.Encoding.UTF8.GetBytes(body), url, inputHeader, "POST", null, null);//调用接口

建立子文件夹方法和上边的一样,很简单,只是使用同步的方法建立的话,时间太长了,后来就做成了,建立主文件夹成功就启动另外一个线程来建立子文件夹,然后就返回了。

subFolders = SubFolders.Select(x => folderName + "/" + x).ToArray();
Thread thread = new Thread(new ThreadStart(DoCreateSubFolders));
thread.Start();

private string[] subFolders;
private void DoCreateSubFolders()
{
    if(subFolders !=null && subFolders.Length > 0)
    {
        foreach(var s in subFolders)
        {
           CreateFolder(s);
        }
    }
}

第二个需求是列出文件夹的目录,这个先用他们的接口试了试,结果速度太慢了,有点不能接受,后来改成了直接读库。

方案改了之后很顺利,因为 Administrator 用户是固定的,只要在 oc_ldap_user_mapping 表里找到根目录就行了。

var storage = Ioc_StoragesService.GetModelByUserGuid(Administrator根路径);
var rst = Ioc_FilecacheService.GetModelByStorage(storage.numeric_id, folderName);
return rst.Select(x => new OcFileEntity(x, 网盘地址, Request.Scheme + "://" + Request.Host.Value)).ToArray();

第三个需求是下载文件。

由于Nextcloud 本身的下载是需要身份验证的,所以转发肯定是不能用的。然后就想到了,先把文件下载下来,再返回给用户。

WebClient wc = new WebClient();
wc.Headers.Add(HttpRequestHeader.Authorization, $"Basic {cre}");
var folder = System.IO.Path.GetDirectoryName(localpath);

wc.DownloadFile($"{网盘地址}/remote.php/dav/files/{Administrator根目录}/{path}", localpath);

var sr = new FileStream($"{临时文件夹}/" + path, FileMode.Open);
return File(sr, "application/octet-stream", Path.GetFileName(path), true);

这种实现方法要求站点部署时要和网盘服务器近一点(最好是同一台机器)。

欢迎同样对 Nextcloud 做二次开发的朋友们来交流。

你可能感兴趣的:(基于 Nextcloud 的二次开发)