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<oc_accounts>(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 做二次開發的朋友們來交流。