/// <summary> /// Processes a PutUserInfo request /// </summary> /// <remarks> /// For full documentation on PutUserInfo, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/PutUserInfo.html /// </remarks> private async static Task<HttpResponseMessage> PutUserInfo(this HttpContext context, FileModel file) { // Set and save the UserInfo on the file var stream = context.Request.InputStream; var bytes = new byte[stream.Length]; await stream.ReadAsync(bytes, 0, (int)stream.Length); file.UserInfo = System.Text.Encoding.UTF8.GetString(bytes); // Update the file in DocumentDB await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success return returnStatus(HttpStatusCode.OK, "Success"); }
/// <summary> /// Forms the correct action url for the file and host /// </summary> public static string GetActionUrl(WopiAction action, FileModel file, string authority) { // Initialize the urlsrc var urlsrc = action.urlsrc; // Look through the action placeholders var phCnt = 0; foreach (var p in WopiUrlPlaceholders.Placeholders) { if (urlsrc.Contains(p)) { // Replace the placeholder value accordingly var ph = WopiUrlPlaceholders.GetPlaceholderValue(p); if (!String.IsNullOrEmpty(ph)) { urlsrc = urlsrc.Replace(p, ph + "&"); phCnt++; } else urlsrc = urlsrc.Replace(p, ph); } } // Add the WOPISrc to the end of the request urlsrc += ((phCnt > 0) ? "" : "?") + String.Format("WOPISrc=https://{0}/wopi/files/{1}", authority, file.id.ToString()); return urlsrc; }
/// <summary> /// Processes a PutFile request /// </summary> /// <remarks> /// For full documentation on PutFile, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/PutFile.html /// </remarks> private async static Task<HttpResponseMessage> PutFile(this HttpContext context, FileModel file) { // Get the Lock value passed in on the request string requestLock = context.Request.Headers[WopiRequestHeaders.LOCK]; // Ensure the file has a valid lock if (String.IsNullOrEmpty(file.LockValue)) { // If the file is 0 bytes, this is document creation if (context.Request.InputStream.Length == 0) { // Update the file in blob storage var bytes = new byte[context.Request.InputStream.Length]; context.Request.InputStream.Read(bytes, 0, bytes.Length); file.Size = bytes.Length; await AzureStorageUtil.UploadFile(file.id.ToString(), file.Container, bytes); // Update version file.Version++; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } else { // File isn't locked...pass empty Lock in mismatch response return context.returnLockMismatch(String.Empty, "File isn't locked"); } } else if (file.LockExpires != null && file.LockExpires < DateTime.Now) { // File lock expired, so clear it out file.LockValue = null; file.LockExpires = null; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // File isn't locked...pass empty Lock in mismatch response return context.returnLockMismatch(String.Empty, "File isn't locked"); } else if (requestLock != file.LockValue) { // File lock mismatch...pass Lock in mismatch response return context.returnLockMismatch(file.LockValue, "Lock mismatch"); } else { // Update the file in blob storage var bytes = new byte[context.Request.InputStream.Length]; context.Request.InputStream.Read(bytes, 0, bytes.Length); file.Size = bytes.Length; await AzureStorageUtil.UploadFile(file.id.ToString(), file.Container, bytes); // Update version file.Version++; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } }
/// <summary> /// Processes a RenameFile request /// </summary> /// <remarks> /// For full documentation on RenameFile, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/RenameFile.html /// </remarks> private async static Task<HttpResponseMessage> RenameFile(this HttpContext context, FileModel file) { // Get the Lock value passed in on the request string requestLock = context.Request.Headers[WopiRequestHeaders.LOCK]; // Make sure the X-WOPI-RequestedName header is included if (context.Request.Headers[WopiRequestHeaders.REQUESTED_NAME] != null) { // Get the new file name var newFileName = context.Request.Headers[WopiRequestHeaders.REQUESTED_NAME]; // Ensure the file isn't locked if (String.IsNullOrEmpty(file.LockValue) || (file.LockExpires != null && file.LockExpires < DateTime.Now)) { // Update the file with a LockValue and LockExpiration file.LockValue = requestLock; file.LockExpires = DateTime.Now.AddMinutes(30); file.BaseFileName = newFileName; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } else if (file.LockValue == requestLock) { // File lock matches existing lock, so we can change the name file.LockExpires = DateTime.Now.AddMinutes(30); file.BaseFileName = newFileName; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); return returnStatus(HttpStatusCode.OK, "Success"); } else { // The file is locked by someone else...return mismatch return context.returnLockMismatch(file.LockValue, String.Format("File locked by {0}", file.LockValue)); } } else { // X-WOPI-RequestedName header wasn't included return returnStatus(HttpStatusCode.BadRequest, "X-WOPI-RequestedName header wasn't included in request"); } }
/// <summary> /// Processes a UnlockAndRelock request /// </summary> /// <remarks> /// For full documentation on UnlockAndRelock, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/UnlockAndRelock.html /// </remarks> private async static Task<HttpResponseMessage> UnlockAndRelock(this HttpContext context, FileModel file) { // Get the Lock and OldLock values passed in on the request string requestLock = context.Request.Headers[WopiRequestHeaders.LOCK]; string requestOldLock = context.Request.Headers[WopiRequestHeaders.OLD_LOCK]; // Ensure the file has a valid lock if (String.IsNullOrEmpty(file.LockValue)) { // File isn't locked...pass empty Lock in mismatch response return context.returnLockMismatch(String.Empty, "File isn't locked"); } else if (file.LockExpires != null && file.LockExpires < DateTime.Now) { // File lock expired, so clear it out file.LockValue = null; file.LockExpires = null; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // File isn't locked...pass empty Lock in mismatch response return context.returnLockMismatch(String.Empty, "File isn't locked"); } else if (requestOldLock != file.LockValue) { // File lock mismatch...pass Lock in mismatch response return context.returnLockMismatch(file.LockValue, "Lock mismatch"); } else { // Update the file with a LockValue and LockExpiration file.LockValue = requestLock; file.LockExpires = DateTime.Now.AddMinutes(30); await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } }
/// <summary> /// Processes a GetLock request /// </summary> /// <remarks> /// For full documentation on GetLock, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/GetLock.html /// </remarks> private async static Task<HttpResponseMessage> GetLock(this HttpContext context, FileModel file) { // Check for valid lock on file if (String.IsNullOrEmpty(file.LockValue)) { // File is not locked...return empty X-WOPI-Lock header context.Response.Headers[WopiResponseHeaders.LOCK] = String.Empty; // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } else if (file.LockExpires != null && file.LockExpires < DateTime.Now) { // File lock expired, so clear it out file.LockValue = null; file.LockExpires = null; await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // File is not locked...return empty X-WOPI-Lock header context.Response.Headers[WopiResponseHeaders.LOCK] = String.Empty; // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } else { // File has a valid lock, so we need to return it context.Response.Headers[WopiResponseHeaders.LOCK] = file.LockValue; // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } }
/// <summary> /// Processes a Lock request /// </summary> /// <remarks> /// For full documentation on Lock, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/Lock.html /// </remarks> private async static Task<HttpResponseMessage> Lock(this HttpContext context, FileModel file) { // Get the Lock value passed in on the request string requestLock = context.Request.Headers[WopiRequestHeaders.LOCK]; // Ensure the file isn't already locked or expired if (String.IsNullOrEmpty(file.LockValue) || (file.LockExpires != null && file.LockExpires < DateTime.Now)) { // Update the file with a LockValue and LockExpiration file.LockValue = requestLock; file.LockExpires = DateTime.Now.AddMinutes(30); await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 return returnStatus(HttpStatusCode.OK, "Success"); } else if (file.LockValue == requestLock) { // File lock matches existing lock, so refresh lock by extending expiration file.LockExpires = DateTime.Now.AddMinutes(30); await DocumentDBRepository<FileModel>.UpdateItemAsync("Files", file.id.ToString(), (FileModel)file); // Return success 200 HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); return returnStatus(HttpStatusCode.OK, "Success"); } else { // The file is locked by someone else...return mismatch return context.returnLockMismatch(file.LockValue, String.Format("File already locked by {0}", file.LockValue)); } }
/// <summary> /// Processes a GetFile request /// </summary> /// <remarks> /// For full documentation on GetFile, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/GetFile.html /// </remarks> private async static Task<HttpResponseMessage> GetFile(this HttpContext context, FileModel file) { // Get the file from blob storage var bytes = await AzureStorageUtil.GetFile(file.id.ToString(), file.Container); // Write the response and return success 200 var response = returnStatus(HttpStatusCode.OK, "Success"); response.Content = new ByteArrayContent(bytes); return response; }
/// <summary> /// Processes a CheckFileInfo request /// </summary> /// <remarks> /// For full documentation on CheckFileInfo, see https://wopi.readthedocs.org/projects/wopirest/en/latest/files/CheckFileInfo.html /// </remarks> private static HttpResponseMessage CheckFileInfo(this HttpContext context, FileModel file) { // Serialize the response object string jsonString = JsonConvert.SerializeObject(file); // Write the response and return a success 200 var response = returnStatus(HttpStatusCode.OK, "Success"); response.Content = new StringContent(jsonString); return response; }