Compare commits

..

118 Commits

Author SHA1 Message Date
9e34ed7f67 Merge pull request #172 from ONLYOFFICE/feature/wopi
Feature/wopi
2021-06-21 16:07:53 +03:00
eee6246d0c nodejs: get discovery on wopi page only (9295d83609) 2021-06-21 16:03:56 +03:00
36513d3544 nodejs: stop retrying 2021-06-21 15:42:38 +03:00
fafc3d3d4f nodejs: license 2021-06-21 15:23:29 +03:00
c1e4abf362 Merge remote-tracking branch 'remotes/origin/develop' into feature/wopi 2021-06-21 15:14:49 +03:00
06c1c1bf21 nodejs: copyright 2021-06-21 15:14:32 +03:00
24a2e0bd14 nodejs: move wopi config 2021-06-21 15:12:21 +03:00
05cd67a2f1 Merge pull request #158 from ONLYOFFICE/hellonadya-patch-1-1
Update README.md
2021-06-21 11:25:13 +03:00
6f691b6b9f Update Users (#171)
Small issues with English fixed
2021-06-21 10:41:48 +03:00
85e3f83d84 Merge remote-tracking branch 'remotes/origin/release/v6.4.0' into develop 2021-06-18 11:07:30 +03:00
b00a4dba31 update document templates 2021-06-18 11:07:11 +03:00
3d12d3c38c Merge pull request #170 from ONLYOFFICE/feature/comment-group
Comment groups examples
2021-06-17 12:07:20 +03:00
5d0f190dc8 change full permission value for commentGroups 2021-06-17 12:05:45 +03:00
2782f8f9bd Merge remote-tracking branch 'remotes/origin/develop' into feature/comment-group
# Conflicts:
#	web/documentserver-example/csharp-mvc/Helpers/Users.cs
#	web/documentserver-example/csharp/Users.cs
#	web/documentserver-example/java/src/main/java/entities/FileModel.java
#	web/documentserver-example/java/src/main/java/entities/User.java
#	web/documentserver-example/java/src/main/java/helpers/Users.java
#	web/documentserver-example/nodejs/helpers/users.js
#	web/documentserver-example/php/users.php
#	web/documentserver-example/python/src/utils/users.py
#	web/documentserver-example/ruby/app/models/users.rb
2021-06-17 10:11:07 +03:00
54ed6d8913 Merge pull request #169 from ONLYOFFICE/feature/create-blank-and-with-sample-document
Сreated blank and with sample content document, and removed ability to Create New for anonymous users
2021-06-16 17:02:12 +03:00
75e14c9452 added a description for users about creating a file from the editor 2021-06-16 16:56:25 +03:00
e1b800aa69 php: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:56:16 +03:00
4e69a7dfa5 ruby: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:54:38 +03:00
61cbba05f3 python: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:53:33 +03:00
ab03bb5490 nodejs: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:51:56 +03:00
1deeade91e java: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:50:37 +03:00
417bd3b9f2 csharp-mvc: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:48:48 +03:00
c3fa000cea csharp: added the ability to Create New from templates for user "John Smith" 2021-06-16 16:46:28 +03:00
f8484cfe0e csharp-mvc: changed users description 2021-06-16 15:53:54 +03:00
b396419d05 csharp: changed users description 2021-06-16 15:53:09 +03:00
2d4490e21a csharp-mvc: added commentGroups and sets comment permissions 2021-06-16 15:41:23 +03:00
61295628de csharp: added commentGroups and sets comment permissions 2021-06-16 15:39:33 +03:00
90c7a8440e php: permissions information 2021-06-16 08:09:00 +02:00
40eada3a17 java: new sets of comment permissions to demonstate comment groups 2021-06-15 16:26:03 +02:00
66d977abaf ruby: new sets of comment permissions to demonstate comment groups 2021-06-15 16:14:28 +02:00
e259b303be python: new sets of comment permissions to demonstate comment groups 2021-06-15 16:08:37 +02:00
4d091e892e nodejs: new sets of comment permissions to demonstate comment groups 2021-06-15 16:03:52 +02:00
34bc5d53ee php: new sets of comment permissions to demonstate comment groups 2021-06-15 15:58:15 +02:00
3b514b7f5f nodejs: users description changes 2021-06-15 14:53:35 +02:00
ee0c1571f6 java: commentGroups 2021-06-15 14:49:52 +02:00
ba5a4e64f5 python: commentGroups 2021-06-15 12:18:34 +02:00
500f93deb8 php: commentGroups 2021-06-15 12:06:18 +02:00
b732f6e8cc ruby: commentGroups 2021-06-15 11:49:56 +02:00
a815d30725 nodejs: commentGroups 2021-06-15 11:16:12 +02:00
b9e70b913a Merge pull request #167 from ONLYOFFICE/release/v6.4.0
Release/v6.4.0
2021-06-04 14:08:57 +03:00
31cd3c2dad Merge pull request #166 from ONLYOFFICE/hotfix/v6.3.1
Hotfix/v6.3.1
2021-06-04 14:08:28 +03:00
2082d24132 nodejs: wopi: edit icons 2021-06-01 13:36:03 +03:00
cdf629e863 nodejs: wopi: return correct version 2021-06-01 13:24:17 +03:00
6b8623795d nodejs: wopi: fixed an issue with version key 2021-06-01 13:24:04 +03:00
38e32a69f8 nodejs: wopi: fixed response headers 2021-06-01 12:39:33 +03:00
3180d00b2d nodejs: wopi: return user friendly name 2021-06-01 12:26:30 +03:00
9d3f4731d6 nodejs: wopi: return version header after putFile 2021-06-01 12:26:09 +03:00
f44659ac7c nodejs: wopi: retry discovery 2021-06-01 12:25:34 +03:00
badc6644c2 Merge pull request #164 from ONLYOFFICE/feature/document-password
Fixed password bug for blank document
2021-05-31 13:51:53 +03:00
3bf8d72454 ruby: fixed bug for setting and removing password for blank document 2021-05-31 13:44:05 +03:00
aebcbe058e python: fixed bug for setting and removing password for blank document 2021-05-31 13:42:27 +03:00
15de3e414f php: fixed bug for setting and removing password for blank document 2021-05-31 13:42:27 +03:00
f3718a0f44 java: fixed bug for setting and removing password for blank document 2021-05-31 13:42:27 +03:00
6227d9c965 nodejs: fixed bug for setting and removing password for blank document 2021-05-31 13:39:02 +03:00
90e7922d7c csharp: fixed bug for setting and removing password for blank document 2021-05-31 13:38:05 +03:00
e3f42fffba csharp-mvc: fixed bug for setting and removing password for blank document 2021-05-31 13:30:24 +03:00
6ea3293a96 Merge pull request #159 from ONLYOFFICE/feature/mentions
Add mentions
2021-05-31 12:44:47 +03:00
b36668468e added description by mentions for anonymous user 2021-05-31 10:22:56 +03:00
5c3c0b4361 Merge remote-tracking branch 'remotes/origin/develop' into feature/mentions 2021-05-31 10:02:04 +03:00
a9b82a299a [run] Port (#165)
Change develop port 8001 -> 8000
2021-05-31 09:25:59 +03:00
07d11f0bae fixed the no ability to add mentions for anonymous users 2021-05-28 15:10:06 +03:00
60992ecb38 variable users renamed to usersForMentions 2021-05-26 17:01:47 +03:00
af4cfa8074 nodejs: wopi: correct user 2021-05-25 17:37:01 +03:00
922143bf37 nodejs: wopi: default click action 2021-05-25 17:35:27 +03:00
6d0312feee nodejs: wopi: fixed access_token_ttl 2021-05-25 17:31:33 +03:00
d876e04b9e nodejs: wopi: fixed file versioning 2021-05-25 17:30:39 +03:00
9295d83609 nodejs: wopi: load discovery on start 2021-05-25 17:30:11 +03:00
6c022134d0 ruby: removed the ability to add mentions for anonymous users 2021-05-21 17:36:47 +03:00
97fc45a15c python: removed the ability to add mentions for anonymous users 2021-05-21 17:33:27 +03:00
487adb11a7 php: removed the ability to add mentions for anonymous users 2021-05-21 17:32:43 +03:00
c052bbae31 nodejs: removed the ability to add mentions for anonymous users 2021-05-21 17:31:15 +03:00
667ff98142 java: removed the ability to add mentions for anonymous users 2021-05-21 17:29:29 +03:00
304d628dbe csharp-mvc: removed the ability to add mentions for anonymous users 2021-05-21 17:28:20 +03:00
50b9aa4296 csharp: removed the ability to add mentions for anonymous users 2021-05-21 17:26:47 +03:00
76dd0b6d7b java: add mentions 2021-05-21 10:17:55 +03:00
25ccda7e89 python: add mentions 2021-05-21 10:15:20 +03:00
b3dd5bc15d ruby: add mentions 2021-05-21 10:15:19 +03:00
46961db654 Merge branch release/v6.3.0 into master 2021-05-20 11:58:44 +00:00
4790aa074e php: add mentions 2021-05-20 10:57:17 +03:00
0392ffbc9a csharp: add mentions 2021-05-20 10:53:43 +03:00
b6b980de92 mvc: mentions 2021-05-20 10:53:31 +03:00
06e93c5b0f Update README.md 2021-05-17 17:51:06 +03:00
d75bcb85c9 Update readme.md 2021-05-17 17:49:47 +03:00
c1bd8458fb Update README.md 2021-05-17 17:49:08 +03:00
bd2a94176e Update README.md 2021-05-17 17:47:17 +03:00
c16359b1c0 Update README.md 2021-05-17 17:46:27 +03:00
73f7b31bfa Update README.md 2021-05-17 17:45:03 +03:00
2ea4dbf289 Update README.md 2021-05-17 17:43:26 +03:00
cb54ca9821 Update README.md 2021-05-17 17:37:31 +03:00
0278fd05e2 Update README.md 2021-05-17 17:31:43 +03:00
511301260b Update readme.md 2021-05-17 16:55:44 +03:00
0e454c8def Update README.md 2021-05-17 16:54:38 +03:00
334f60cdac Update README.md 2021-05-17 16:34:21 +03:00
fecc69a00e Update README.md 2021-05-17 16:20:41 +03:00
22cf4c7c24 Update README.md 2021-05-17 16:19:59 +03:00
c780ed127c Update README.md 2021-05-17 16:18:52 +03:00
9cea54a949 Update README.md 2021-05-17 15:25:56 +03:00
4d3059ffa0 Update README.md 2021-05-17 15:20:59 +03:00
22179d6c4f Update README.md 2021-05-17 11:25:49 +03:00
9dd43e892b Update README.md 2021-05-17 11:18:52 +03:00
675511fb0e Update README.md 2021-05-17 11:13:58 +03:00
bfc7ee2ad6 Update README.md 2021-05-17 11:13:36 +03:00
c03e4f3896 Update README.md 2021-05-17 11:13:04 +03:00
f23f0bd3d3 Update README.md 2021-05-14 18:27:30 +03:00
f451a7032d Update README.md
- MD in accordance with ONLYOFFICE README style
- Minor improvements
2021-05-14 17:54:15 +03:00
312209cd5a nodejs: wopi locks 2021-05-06 16:13:51 +03:00
fa346a0c27 nodejs: fixed an issue with sending response twice 2021-05-06 16:13:24 +03:00
12f88044b7 Merge remote-tracking branch 'origin/develop' into feature/wopi
# Conflicts:
#	web/documentserver-example/nodejs/app.js
2021-04-28 13:19:37 +03:00
0e0eea3ebd nodejs: wopi ui 2021-04-28 13:10:41 +03:00
b5ef247245 nodejs: wopi create file 2021-04-28 11:58:59 +03:00
5645a0fc2c nodejs: wopi edit 2021-04-28 11:58:39 +03:00
a9a48d5816 nodejs: add mentions 2021-04-26 13:27:03 +03:00
b6cb5150dd nodejs: fix development version 2021-04-22 18:50:40 +03:00
667b9abc0d view files 2021-04-22 11:59:20 +03:00
e34cdf0098 dev config 2021-04-22 11:58:49 +03:00
e321503dca wopi config 2021-04-21 17:59:12 +03:00
4d64347fb9 added fast-xml-parser to dep 2021-04-21 17:58:53 +03:00
bfb202dd4f wopi readonly 2021-04-21 17:58:37 +03:00
67 changed files with 2272 additions and 414 deletions

View File

@ -112,10 +112,18 @@ express - Fast, unopinionated, minimalist web framework for node. (https:/
License: MIT
License File: express.license
fast-xml-parser - Validate XML, Parse XML to JS/JSON and vice versa, or parse XML to Nimn rapidly without C/C++ based libraries and no callback. (https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/LICENSE)
License: MIT
License File: fast-xml-parser.license
formidable - A Node.js module for parsing form data, especially file uploads. (https://github.com/node-formidable/formidable/blob/master/LICENSE)
License: MIT
License File: formidable.license
he - a robust HTML entity encoder/decoder written in JavaScript. (https://github.com/mathiasbynens/he/blob/master/LICENSE-MIT.txt)
License: MIT
License File: he.license
jQuery - jQuery is a new kind of JavaScript Library. jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript. NOTE: This package is maintained on behalf of the library owners by the NuGet Community Packages project at https://nugetpackages.codeplex.com/ (https://jquery.org/license/)
License: MIT
License File: jQuery.license

View File

@ -308,6 +308,28 @@ namespace OnlineEditorsExampleMVC.Helpers
}
}
// get image url for templates
public static string GetTemplateImageUrl(FileUtility.FileType fileType)
{
var path = new UriBuilder(GetServerUrl(true)) // templates image url in the "From Template" section
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "Content\\images\\"
};
switch (fileType)
{
case FileUtility.FileType.Word: // for word file type
return path + "file_docx.svg";
case FileUtility.FileType.Cell: // for cell file type
return path + "file_xlsx.svg";
case FileUtility.FileType.Slide: // for slide file type
return path + "file_pptx.svg";
default:
return path + "file_docx.svg"; // the default value
}
}
// get file information
public static List<Dictionary<string, object>> GetFilesInfo(string fileId = null)
{

View File

@ -17,6 +17,7 @@
*/
using System.Collections.Generic;
using System.Linq;
namespace OnlineEditorsExampleMVC.Helpers
{
@ -25,43 +26,106 @@ namespace OnlineEditorsExampleMVC.Helpers
static List<string> descr_user_1 = new List<string>()
{
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
};
static List<string> descr_user_2 = new List<string>()
{
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
};
static List<string> descr_user_3 = new List<string>()
{
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
};
static List<string> descr_user_0 = new List<string>()
{
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
};
private static List<User> users = new List<User>() {
new User("uid-1", "John Smith", "smith@mail.ru", null, null, null, new List<string>(), descr_user_1),
new User("uid-2", "Mark Pottato", "pottato@mail.ru", "group-2", new List<string>() { "group-2", "" }, true, new List<string>(), descr_user_2),
new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru", "group-3", new List<string>() { "group-2" }, false, new List<string>() { "copy", "download", "print" }, descr_user_3),
new User("uid-0", null, null, null, null, null, new List<string>(), descr_user_0)
new User(
"uid-1",
"John Smith",
"smith@mail.ru",
null,
null,
new Dictionary<string, object>(),
null,
new List<string>(),
descr_user_1,
true
),
new User(
"uid-2",
"Mark Pottato",
"pottato@mail.ru",
"group-2",
new List<string>() { "group-2", "" },
new Dictionary<string, object>()
{
{ "view", "" },
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
true,
new List<string>(),
descr_user_2,
false
),
new User(
"uid-3",
"Hamish Mitchell",
"mitchell@mail.ru",
"group-3",
new List<string>() { "group-2" },
new Dictionary<string,object>()
{
{ "view", new List<string>() { "group-2", "group-3" } },
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
false
),
new User(
"uid-0",
null,
null,
null,
null,
new Dictionary<string,object>(),
null,
new List<string>(),
descr_user_0,
false
)
};
public static User getUser(string id)
{
foreach(User user in users)
@ -75,6 +139,23 @@ namespace OnlineEditorsExampleMVC.Helpers
{
return users;
}
public static List<Dictionary<string, object>> getUsersForMentions(string id)
{
List<Dictionary<string, object>> usersData = new List<Dictionary<string, object>>();
foreach (User user in users)
{
if (!user.id.Equals(id) && user.name != null && user.email != null)
{
usersData.Add(new Dictionary<string, object>()
{
{"name", user.name },
{"email", user.email }
});
}
}
return usersData;
}
}
public class User
@ -84,21 +165,24 @@ namespace OnlineEditorsExampleMVC.Helpers
public string email;
public string group;
public List<string> reviewGroups;
public Dictionary<string, object> commentGroups;
public bool? favorite;
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public User(string id, string name, string email, string group, List<string> reviewGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
this.email = email;
this.group = group;
this.reviewGroups = reviewGroups;
this.commentGroups = commentGroups;
this.favorite = favorite;
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
}
}
}
}

View File

@ -65,11 +65,6 @@ namespace OnlineEditorsExampleMVC.Models
get { return DocManagerHelper.GetCallback(FileName); }
}
public string CreateUrl
{
get { return DocManagerHelper.GetCreateUrl(FileUtility.GetFileType(FileName)); }
}
public string DownloadUrl
{
get { return DocManagerHelper.GetDownloadUrl(FileName); }
@ -96,6 +91,24 @@ namespace OnlineEditorsExampleMVC.Models
var actionLink = request.GetOrDefault("actionLink", null); // get the action link (comment or bookmark) if it exists
var actionData = string.IsNullOrEmpty(actionLink) ? null : jss.DeserializeObject(actionLink); // get action data for the action link
var createUrl = DocManagerHelper.GetCreateUrl(FileUtility.GetFileType(FileName));
var templatesImageUrl = DocManagerHelper.GetTemplateImageUrl(FileUtility.GetFileType(FileName)); // image url for templates
var templates = new List<Dictionary<string, string>>
{
new Dictionary<string, string>()
{
{ "image", templatesImageUrl },
{ "title", "Blank" },
{ "url", createUrl },
},
new Dictionary<string, string>()
{
{ "image", templatesImageUrl },
{ "title", "With sample content" },
{ "url", createUrl + "&sample=true" },
}
};
// specify the document config
var config = new Dictionary<string, object>
{
@ -129,7 +142,8 @@ namespace OnlineEditorsExampleMVC.Models
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "reviewGroups", user.reviewGroups }
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups }
}
}
}
@ -141,7 +155,8 @@ namespace OnlineEditorsExampleMVC.Models
{ "mode", mode },
{ "lang", request.Cookies.GetOrDefault("ulang", "en") },
{ "callbackUrl", CallbackUrl }, // absolute URL to the document storage service
{ "createUrl", CreateUrl },
{ "createUrl", !user.id.Equals("uid-0") ? createUrl : null },
{ "templates", user.templates ? templates : null },
{
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
@ -241,13 +256,16 @@ namespace OnlineEditorsExampleMVC.Models
{
// get the path to the changes.json file
var changes = jss.Deserialize<Dictionary<string, object>>(File.ReadAllText(Path.Combine(DocManagerHelper.VersionDir(histDir, i - 1), "changes.json")));
var change = ((Dictionary<string, object>)((ArrayList)changes["changes"])[0]);
var changesArray = (ArrayList)changes["changes"];
var change = changesArray.Count > 0
? (Dictionary<string, object>)changesArray[0]
: new Dictionary<string, object>();
// write information about changes to the object
obj.Add("changes", changes["changes"]);
obj.Add("changes", change.Count > 0 ? changes["changes"] : null);
obj.Add("serverVersion", changes["serverVersion"]);
obj.Add("created", change["created"]);
obj.Add("user", change["user"]);
obj.Add("created", change.Count > 0 ? change["created"] : null);
obj.Add("user", change.Count > 0 ? change["user"] : null);
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
@ -365,5 +383,14 @@ namespace OnlineEditorsExampleMVC.Models
dataMailMergeRecipients = jss.Serialize(mailMergeConfig);
}
//get a users for mentions
public void GetUsersMentions(HttpRequest request, out string usersForMentions)
{
var jss = new JavaScriptSerializer();
var id = request.Cookies.GetOrDefault("uid", null);
var user = Users.getUser(id);
usersForMentions = !user.id.Equals("uid-0") ? jss.Serialize(Users.getUsersForMentions(user.id)) : null;
}
}
}

View File

@ -149,7 +149,6 @@
<Content Include="favicon.ico" />
<Content Include="Global.asax" />
<Content Include="LICENSE" />
<Content Include="ReadMe.txt" />
<Content Include="Scripts\jquery-1.8.2.js" />
<Content Include="Scripts\jquery-ui.js" />
<Content Include="Scripts\jquery.blockUI.js" />

View File

@ -1,35 +1,34 @@
## How to integrate online editors into your own web site on .Net (C# MVC)
### Introduction
To integrate **ONLYOFFICE online editors** into your own website on **.Net (C# MVC)** you need to download and install ONLYOFFICE editors on your local server and use the [.Net (C# MVC) example](https://api.onlyoffice.com/editors/demopreview) for their integration.
## Overview
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C# MVC).
This guide will show you the sequence of actions to integrate the editors successfully.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
### Step 1. Download and Install Document Server
## Step 1. Install ONLYOFFICE Docs
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_csharp_example), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_csharp_example), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx?from=api_csharp_example).
Download and install ONLYOFFICE Docs (packaged as Document Server).
### Step 2. Download the .Net (C# MVC) code for the editors integration
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
## Step 2. Download the .Net (C# MVC) code for the editors integration
Download the [.Net (C# MVC) example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connnect the editors to your web site. For that specify the path to the editors installation in the *settings.config* file:
You need to connnect the editors to your web site. Specify path to the editors installation in the *settings.config* file:
```
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *DocEditor.aspx* file.
### Step 3. Install the prerequisites
To run your website with the editors successfully, check if your system meets the necessary system requirements:
## Step 3. Install the prerequisites
Сheck if your system meets the system requirements:
* Microsoft .NET Framework: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* Internet Information Services: version 7 or later.
### Step 4. Running your web site with the editors
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) manager
Start -> ControlPanel -> System and Security -> Administrative Tools -> Internet Information Services (IIS) Manager
2. Add your web site in the IIS Manager
2. Add your website in the IIS Manager
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
3. In the **Add Website** dialog box specify the name of the folder with the .Net (C# MVC) project in the **Site name** box.
@ -39,11 +38,12 @@ To run your website with the editors successfully, check if your system meets th
4. Check for the .NET platform version specified in IIS manager for you web site. Choose **v4.0.** version.
Click the **Application Pool** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
5. Browse your web site with the IIS manager:
5. Browse your website with the IIS manager:
Right-click the site -> **Manage Website** -> **Browse**
![browse](screenshots/browse.png)
### Step 5. Checking accessibility
## Step 5. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -173,6 +173,24 @@
};
<% } %>
<% string usersForMentions; %>
<% Model.GetUsersMentions(Request, out usersForMentions); %>
<% if (!string.IsNullOrEmpty(usersForMentions))
// add mentions for not anonymous users
{ %>
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": <%= usersForMentions%>
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% } %>
var сonnectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -11,7 +11,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="icon" href="<%= "app_themes/images/" + documentType + ".ico" %>" type="image/x-icon" />
<link rel="icon" href="<%= "app_themes/images/" + DocumentType + ".ico" %>" type="image/x-icon" />
<title>ONLYOFFICE</title>
<!--
*
@ -133,18 +133,18 @@
var onRequestInsertImage = function (event) {
docEditor.insertImage({ // insert an image into the file
"c": event.data.c,
<%= InsertImageConfig%>
<%= InsertImageConfig %>
})
};
// the user is trying to select document for comparing by clicking the Document from Storage button
var onRequestCompareFile = function () {
docEditor.setRevisedFile(<%= compareFileData%>); // select a document for comparing
docEditor.setRevisedFile(<%= CompareFileData %>); // select a document for comparing
};
// the user is trying to select recipients data by clicking the Mail merge button
var onRequestMailMergeRecipients = function (event) {
docEditor.setMailMergeRecipients(<%= dataMailMergeRecipients%>); // insert recipient data for mail merge into the file
docEditor.setMailMergeRecipients(<%= DataMailMergeRecipients %>); // insert recipient data for mail merge into the file
};
var config = <%= DocConfig %>;
@ -180,6 +180,22 @@
};
<% } %>
<% if (!string.IsNullOrEmpty(UsersForMentions))
{ %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": <%= UsersForMentions %>
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% } %>
var сonnectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -64,9 +64,10 @@ namespace OnlineEditorsExample
protected string History { get; private set; }
protected string HistoryData { get; private set; }
protected string InsertImageConfig { get; private set; }
protected string compareFileData { get; private set; }
protected string dataMailMergeRecipients { get; private set; }
protected string documentType { get { return _Default.DocumentType(FileName); } }
protected string CompareFileData { get; private set; }
protected string DataMailMergeRecipients { get; private set; }
protected string UsersForMentions { get; private set; }
protected string DocumentType { get { return _Default.DocumentType(FileName); } }
// get callback url
public static string CallbackUrl
@ -160,11 +161,29 @@ namespace OnlineEditorsExample
var actionLink = Request.GetOrDefault("actionLink", null); // get the action link (comment or bookmark) if it exists
var actionData = string.IsNullOrEmpty(actionLink) ? null : jss.DeserializeObject(actionLink); // get action data for the action link
var createUrl = getCreateUrl(DocumentType, editorsType);
var templatesImageUrl = GetTemplateImageUrl(ext); // image url for templates
var templates = new List<Dictionary<string, string>>
{
new Dictionary<string, string>()
{
{ "image", templatesImageUrl },
{ "title", "Blank" },
{ "url", createUrl }
},
new Dictionary<string, string>()
{
{ "image", templatesImageUrl },
{ "title", "With sample content" },
{ "url", createUrl + "&sample=true" }
}
};
// specify the document config
var config = new Dictionary<string, object>
{
{ "type", editorsType },
{ "documentType", documentType },
{ "documentType", DocumentType },
{
"document", new Dictionary<string, object>
{
@ -193,7 +212,8 @@ namespace OnlineEditorsExample
{ "modifyFilter", editorsMode != "filter" },
{ "modifyContentControl", editorsMode != "blockcontent" },
{ "review", canEdit && (editorsMode == "edit" || editorsMode == "review") },
{ "reviewGroups", user.reviewGroups }
{ "reviewGroups", user.reviewGroups },
{ "commentGroups", user.commentGroups }
}
}
}
@ -205,7 +225,8 @@ namespace OnlineEditorsExample
{ "mode", mode },
{ "lang", Request.Cookies.GetOrDefault("ulang", "en") },
{ "callbackUrl", CallbackUrl }, // absolute URL to the document storage service
{ "createUrl", getCreateUrl(documentType, editorsType)},
{ "createUrl", !user.id.Equals("uid-0") ? createUrl : null },
{ "templates", user.templates ? templates : null },
{
// the user currently viewing or editing the document
"user", new Dictionary<string, object>
@ -263,12 +284,15 @@ namespace OnlineEditorsExample
// a document which will be compared with the current document
Dictionary<string, object> compareFile = GetCompareFile();
compareFileData = jss.Serialize(compareFile);
CompareFileData = jss.Serialize(compareFile);
// recipient data for mail merging
Dictionary<string, object> mailMergeConfig = GetMailMergeConfig();
dataMailMergeRecipients = jss.Serialize(mailMergeConfig);
DataMailMergeRecipients = jss.Serialize(mailMergeConfig);
// get users for mentions
List<Dictionary<string, object>> usersData = Users.getUsersForMentions(user.id);
UsersForMentions = !user.id.Equals("uid-0") ? jss.Serialize(usersData) : null;
Dictionary<string, object> hist;
Dictionary<string, object> histData;
@ -331,13 +355,16 @@ namespace OnlineEditorsExample
{
// get the path to the changes.json file
var changes = jss.Deserialize<Dictionary<string, object>>(File.ReadAllText(Path.Combine(_Default.VersionDir(histDir, i - 1), "changes.json")));
var change = ((Dictionary<string, object>)((ArrayList)changes["changes"])[0]);
var changesArray = (ArrayList)changes["changes"];
var change = changesArray.Count > 0
? (Dictionary<string, object>)changesArray[0]
: new Dictionary<string, object>();
// write information about changes to the object
obj.Add("changes", changes["changes"]);
obj.Add("changes", change.Count > 0 ? changes["changes"] : null);
obj.Add("serverVersion", changes["serverVersion"]);
obj.Add("created", change["created"]);
obj.Add("user", change["user"]);
obj.Add("created", change.Count > 0 ? change["created"] : null);
obj.Add("user", change.Count > 0 ? change["user"] : null);
var prev = (Dictionary<string, object>)histData[(i - 2).ToString()]; // get the history data from the previous file version
dataObj.Add("previous", new Dictionary<string, object>() { // write information about previous file version to the data object
@ -444,6 +471,28 @@ namespace OnlineEditorsExample
return mailMergeConfig;
}
// get image url for templates
private string GetTemplateImageUrl (string ext)
{
var path = new UriBuilder(_Default.GetServerUrl(true)) // templates image url in the "From Template" section
{
Path = HttpRuntime.AppDomainAppVirtualPath
+ (HttpRuntime.AppDomainAppVirtualPath.EndsWith("/") ? "" : "/")
+ "App_Themes\\images\\"
};
switch (ext)
{
case ".docx":
return path + "file_docx.svg"; // for word document type
case ".xlsx":
return path + "file_xlsx.svg"; // .xlsx for cell document type
case ".pptx":
return path + "file_pptx.svg"; // .pptx for slide document type
default:
return path + "file_docx.svg"; // the default value
}
}
// create the public url
private string MakePublicUrl(string fullPath)
{

View File

@ -91,7 +91,6 @@
<Content Include="App_Themes\images\word.ico" />
<Content Include="LICENSE" />
<Content Include="licenses\jquery.license" />
<Content Include="ReadMe.txt" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>

View File

@ -1,49 +1,52 @@
## How to integrate online editors into your own web site on .Net (C#)
### Introduction
To integrate **ONLYOFFICE online editors** into your own website on **.Net (C#)** you need to download and install ONLYOFFICE editors on your local server and use the [.Net (C#) example](https://api.onlyoffice.com/editors/demopreview) for their integration.
## Overview
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
This example will help you integrate ONLYOFFICE Docs into your web application written in .Net (C#).
This guide will show you the sequence of actions to integrate the editors successfully.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
### Step 1. Download and Install Document Server
## Step 1. Install ONLYOFFICE Docs
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_csharp_example), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_csharp_example), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx?from=api_csharp_example).
Download and install ONLYOFFICE Docs (packaged as Document Server).
### Step 2. Download the .Net (C#) code for the editors integration
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
## Step 2. Download the .Net (C#) code for the editors integration
Download the [.Net (C#) example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connnect the editors to your web site. For that specify the path to the editors installation in the *settings.config* file:
Connect the editors to your website by specifying the path to the editors installation in the *settings.config* file:
```
<add key="files.docservice.url.site" value="https://documentserver/" />
```
where the **documentserver** is the name of the server with the ONLYOFFICE Document Server installed.
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *DocEditor.aspx* file.
### Step 3. Install the prerequisites
To run your website with the editors successfully, check if your system meets the necessary system requirements:
## Step 3. Install the prerequisites
Check that your system meets the requirements:
* Microsoft .NET Framework: version 4.5 (download it from the [official Microsoft website](https://www.microsoft.com/en-US/download/details.aspx?id=30653));
* Internet Information Services: version 7 or later.
### Step 4. Running your web site with the editors
## Step 4. Run your website with the editors
1. Run the Internet Information Service (IIS) manager
Start -> ControlPanel -> System and Security -> Administrative Tools -> Internet Information Services (IIS) Manager
2. Add your web site in the IIS Manager
2. Add your website in the IIS Manager
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
![add](screenshots/add.png)
3. In the **Add Website** dialog box specify the name of the folder with the .Net (C#) project in the **Site name** box.
Specify the path to the folder with your project in the **Physical Path** box.
Specify the unique value used only for this website in the **Port** box.
![sitename](screenshots/sitename.png)
4. Check for the .NET platform version specified in IIS manager for you web site. Choose **v4.0.** version.
4. Check for the .NET platform version specified in IIS manager for you website. Choose **v4.0.** version.
Click the **Application Pool** -> right-click the platform name -> **Set application Pool defaults** -> **.NET CLR version**
![platform](screenshots/platform.png)
5. Browse your web site with the IIS manager:
5. Browse your website with the IIS manager:
Right-click the site -> **Manage Website** -> **Browse**
![browse](screenshots/browse.png)
### Step 5. Checking accessibility
## Step 5. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -25,41 +25,104 @@ namespace OnlineEditorsExample
static List<string> descr_user_1 = new List<string>()
{
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
};
static List<string> descr_user_2 = new List<string>()
{
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
};
static List<string> descr_user_3 = new List<string>()
{
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
};
static List<string> descr_user_0 = new List<string>()
{
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
};
private static List<User> users = new List<User>() {
new User("uid-1", "John Smith", "smith@mail.ru", null, null, null, new List<string>(), descr_user_1),
new User("uid-2", "Mark Pottato", "pottato@mail.ru", "group-2", new List<string>() { "group-2", "" }, true, new List<string>(), descr_user_2),
new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru", "group-3", new List<string>() { "group-2" }, false, new List<string>() { "copy", "download", "print" }, descr_user_3),
new User("uid-0", null, null, null, null, null, new List<string>(), descr_user_0)
new User(
"uid-1",
"John Smith",
"smith@mail.ru",
null,
null,
new Dictionary<string, object>(),
null,
new List<string>(),
descr_user_1,
true
),
new User(
"uid-2",
"Mark Pottato",
"pottato@mail.ru",
"group-2",
new List<string>() { "group-2", "" },
new Dictionary<string, object>()
{
{ "view", "" },
{ "edit", new List<string>() { "group-2", "" } },
{ "remove", new List<string>() { "group-2" } }
},
true,
new List<string>(),
descr_user_2,
false
),
new User(
"uid-3",
"Hamish Mitchell",
"mitchell@mail.ru",
"group-3",
new List<string>() { "group-2" },
new Dictionary<string,object>()
{
{ "view", new List<string>() { "group-2", "group-3" } },
{ "edit", new List<string>() { "group-2" } },
{ "remove", new List<string>() { } }
},
false,
new List<string>() { "copy", "download", "print" },
descr_user_3,
false
),
new User(
"uid-0",
null,
null,
null,
null,
new Dictionary<string, object>(),
null,
new List<string>(),
descr_user_0,
false
)
};
public static User getUser(string id)
@ -75,6 +138,24 @@ namespace OnlineEditorsExample
{
return users;
}
public static List<Dictionary<string, object>> getUsersForMentions(string id)
{
List<Dictionary<string, object>> usersData = new List<Dictionary<string, object>>();
foreach (User user in users)
{
if (!user.id.Equals(id) && user.name != null && user.email != null)
{
usersData.Add(new Dictionary<string, object>()
{
{"name", user.name },
{"email", user.email },
});
}
}
return usersData;
}
}
public class User
@ -84,21 +165,24 @@ namespace OnlineEditorsExample
public string email;
public string group;
public List<string> reviewGroups;
public Dictionary<string, object> commentGroups;
public bool? favorite;
public List<string> deniedPermissions;
public List<string> descriptions;
public bool templates;
public User(string id, string name, string email, string group, List<string> reviewGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions)
public User(string id, string name, string email, string group, List<string> reviewGroups, Dictionary<string, object> commentGroups, bool? favorite, List<string> deniedPermissions, List<string> descriptions, bool templates)
{
this.id = id;
this.name = name;
this.email = email;
this.group = group;
this.reviewGroups = reviewGroups;
this.commentGroups = commentGroups;
this.favorite = favorite;
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
}
}
}
}

View File

@ -1,28 +1,22 @@
# How to integrate online editors into your own web site on Java
## Overview
## Introduction
This example will help you integrate ONLYOFFICE Docs into your web application written in Java.
To integrate **ONLYOFFICE online editors** into your own website on **Java** you need to download and install ONLYOFFICE editors on your local server and use the [Java Example](https://api.onlyoffice.com/editors/demopreview) for their integration.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
You can choose any appropriate way how to run the Java example code. We will show how to run the Java code using the **Apache Tomcat** web server on [Windows OS](#running-the-example-on-windows-os) and [Linux OS](#running-the-example-on-linux-os).
## For Windows
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
### Step 1. Install ONLYOFFICE Docs
This guide will show you the sequence of actions to integrate the editors successfully.
Download and install ONLYOFFICE Docs (packaged as Document Server).
## Running the example on Windows OS
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
## Step 1. Download and Install Document Server
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_java_example).
## Step 2. Download the Java code for the editors integration
### Step 2. Download the Java code for the editors integration
Download the [Java example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connect the editors to your web site. For that specify the path to the editors installation in the *\src\main\resources\settings.properties* file:
To connect the editors to your website, specify the path to the editors installation in the *\src\main\resources\settings.properties* file:
```
files.docservice.url.site=https://documentserver/
@ -32,16 +26,16 @@ where the **documentserver** is the name of the server with the ONLYOFFICE Docum
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *\src\main\webapp\editor.jsp* file.
## Step 3. Install the prerequisites
### Step 3. Install the prerequisites
To run the Java example code you will need to install the Java version appropriate for your OS and web server **Apache Tomcat**:
To run the Java example code, install the Java version appropriate for your OS and web server **Apache Tomcat**:
* Java (download from [the Oracle official web site](https://www.java.com/en/download/manual.jsp));
* Java (download from [the Oracle official website](https://www.java.com/en/download/manual.jsp));
* Apache Tomcat (download from [the official website](http://tomcat.apache.org/)).
## Step 4. Running Apache Tomcat
### Step 4. Run Apache Tomcat
1. After you have installed Java in Windows, you must set the **JAVA_HOME** environment variable to point to the Java installation directory.
1. After you have installed Java on Windows, set the **JAVA_HOME** environment variable to point to the Java installation directory.
Find out where Java is installed. If you didn't change the path during installation, it will be something like this:
@ -93,7 +87,7 @@ To run the Java example code you will need to install the Java version appropria
If everything is correct, you will see the Tomcat web page in the browser as shown below.
## Step 5 . Running the Java code
### Step 5. Run the Java code
1. Open Tomcat Web Application Manager by clicking **Manager App:**
@ -103,7 +97,7 @@ To run the Java example code you will need to install the Java version appropria
![author](screenshots/author.jpg)
For that you will need to specify user data in *tomcat-users.xml* file in the Apache Tomcat installation folder. Define the **manager-gui** user role, specify the **user name** and **password** values:
Specify user data in *tomcat-users.xml* file in the Apache Tomcat installation folder. Define the **manager-gui** user role, specify the **user name** and **password** values:
```
<tomcat-users>
@ -121,21 +115,21 @@ To run the Java example code you will need to install the Java version appropria
5. Click the link with the application name to run it.
## Step 6. Checking accessibility
### Step 6. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Running the example on Linux OS
## For Linux
## Step 1. Download and Install Document Server
### Step 1. Install ONLYOFFICE Docs
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to [install Document Server for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_java_example).
See the detailed guide to learn how to install Document Server [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx).
## Step 2. Install the prerequisites and run the web site with the editors
### Step 2. Install the prerequisites and run the website with the editors
1. Install **Java**:
@ -226,15 +220,15 @@ See the detailed guide to learn how to [install Document Server for Linux](https
http://localhost:8080/OnlineEditorsExampleJava-1.0/
```
## Step 3. Checking accessibility
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Build from Docker
## For Docker
1. Edit the *settings.properties* configuration file. Specify the name of your local server with the ONLYOFFICE Document Server installed.
1. Edit the *settings.properties* configuration file. Specify the name of your local server with the ONLYOFFICE Document Server installed ([installation instructions](https://helpcenter.onlyoffice.com/installation/docs-developer-install-docker.aspx)).
```
nano src/main/resources/settings.properties
@ -254,4 +248,4 @@ If you integrated the editors successfully the result should look like the [demo
docker-compose up
```
4. After it, all the *bin* files will be passed to the *./target* folder.
4. After it, all the *bin* files will be passed to the *./target* folder.

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
@ -88,6 +89,9 @@ public class EditorServlet extends HttpServlet
dataMailMergeRecipients.put("fileType", "csv");
dataMailMergeRecipients.put("url", DocumentManager.GetServerUrl(true) + "/IndexServlet?type=csv");
// users data for mentions
List<Map<String, Object>> usersForMentions = Users.getUsersForMentions(user.id);
// check if the document token is enabled
if (DocumentManager.TokenEnabled())
{
@ -103,6 +107,7 @@ public class EditorServlet extends HttpServlet
request.setAttribute("dataInsertImage", gson.toJson(dataInsertImage).substring(1, gson.toJson(dataInsertImage).length()-1));
request.setAttribute("dataCompareFile", gson.toJson(dataCompareFile));
request.setAttribute("dataMailMergeRecipients", gson.toJson(dataMailMergeRecipients));
request.setAttribute("usersForMentions", !user.id.equals("uid-0") ? gson.toJson(usersForMentions) : null);
request.getRequestDispatcher("editor.jsp").forward(request, response);
}

View File

@ -0,0 +1,17 @@
package entities;
import java.util.List;
public class CommentGroups {
public List<String> view;
public List<String> edit;
public List<String> remove;
public CommentGroups(){
}
public CommentGroups(List<String> view, List<String> edit, List<String> remove){
this.view = view;
this.edit = edit;
this.remove = remove;
}
}

View File

@ -18,20 +18,20 @@
package entities;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import helpers.DocumentManager;
import helpers.ServiceConverter;
import helpers.FileUtility;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import helpers.DocumentManager;
import helpers.FileUtility;
import helpers.ServiceConverter;
import helpers.Users;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
public class FileModel
{
public String type = "desktop";
@ -61,12 +61,31 @@ public class FileModel
document.info = new Info();
document.info.favorite = user.favorite;
String templatesImageUrl = DocumentManager.GetTemplateImageUrl(FileUtility.GetFileType(fileName));
List<Map<String, String>> templates = new ArrayList<>();
String createUrl = DocumentManager.GetCreateUrl(FileUtility.GetFileType(fileName));
// add templates for the "Create New" from menu option
Map<String, String> templateForBlankDocument = new HashMap<>();
templateForBlankDocument.put("image", templatesImageUrl);
templateForBlankDocument.put("title", "Blank");
templateForBlankDocument.put("url", createUrl);
templates.add(templateForBlankDocument);
Map<String, String> templateForDocumentWithSampleContent = new HashMap<>();
templateForDocumentWithSampleContent.put("image", templatesImageUrl);
templateForDocumentWithSampleContent.put("title", "With sample content");
templateForDocumentWithSampleContent.put("url", createUrl + "&sample=true");
templates.add(templateForDocumentWithSampleContent);
// set the editor config parameters
editorConfig = new EditorConfig(actionData);
editorConfig.callbackUrl = DocumentManager.GetCallback(fileName); // get callback url
editorConfig.createUrl = DocumentManager.GetCreateUrl(FileUtility.GetFileType(fileName));
if (lang != null) editorConfig.lang = lang; // write language parameter to the config
editorConfig.createUrl = !user.id.equals("uid-0") ? createUrl : null;
editorConfig.templates = user.templates ? templates : null;
// write user information to the config (id, name and group)
editorConfig.user.id = user.id;
editorConfig.user.name = user.name;
@ -163,10 +182,10 @@ public class FileModel
JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
// write information about changes to the object
obj.put("changes", changes.get("changes"));
obj.put("changes", !change.isEmpty() ? changes.get("changes") : null);
obj.put("serverVersion", changes.get("serverVersion"));
obj.put("created", change.get("created"));
obj.put("user", change.get("user"));
obj.put("created", !change.isEmpty() ? change.get("created") : null);
obj.put("user", !change.isEmpty() ? change.get("user") : null);
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version
Map<String, Object> prevInfo = new HashMap<String, Object>();
@ -241,6 +260,7 @@ public class FileModel
public Boolean modifyContentControl;
public Boolean review;
public List<String> reviewGroups;
public CommentGroups commentGroups;
// defines what can be done with a document
public Permissions(String mode, String type, Boolean canEdit, User user)
@ -255,6 +275,7 @@ public class FileModel
modifyContentControl = !mode.equals("blockcontent");
review = canEdit && (mode.equals("edit") || mode.equals("review"));
reviewGroups = user.reviewGroups;
commentGroups = user.commentGroups;
}
}
@ -269,8 +290,9 @@ public class FileModel
public HashMap<String, Object> actionLink = null;
public String mode = "edit";
public String callbackUrl;
public String createUrl;
public String lang = "en";
public String createUrl;
public List<Map<String, String>> templates;
public User user;
public Customization customization;
public Embedded embedded;

View File

@ -26,18 +26,23 @@ public class User {
public String email;
public String group;
public List<String> reviewGroups;
public CommentGroups commentGroups;
public Boolean favorite;
public List<String> deniedPermissions;
public List<String> descriptions;
public Boolean templates;
public User(String id, String name, String email, String group, List<String> reviewGroups, Boolean favorite, List<String> deniedPermissions, List<String> descriptions) {
public User(String id, String name, String email, String group, List<String> reviewGroups, CommentGroups commentGroups,
Boolean favorite, List<String> deniedPermissions, List<String> descriptions, Boolean templates) {
this.id = id;
this.name = name;
this.email = email;
this.group = group;
this.reviewGroups = reviewGroups;
this.commentGroups = commentGroups;
this.favorite = favorite;
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
}
}

View File

@ -432,6 +432,26 @@ public class DocumentManager
return ".docx";
}
// get image url for templates
public static String GetTemplateImageUrl(FileType fileType)
{
String path = GetServerUrl(true) + "/css/img/";
// for word file type
if (fileType.equals(FileType.Word))
return path + "file_docx.svg";
// .xlsx for cell file type
if (fileType.equals(FileType.Cell))
return path + "file_xlsx.svg";
// .pptx for slide file type
if (fileType.equals(FileType.Slide))
return path + "file_pptx.svg";
// the default file type
return path + "file_docx.svg";
}
// create document token
public static String CreateToken(Map<String, Object> payloadClaims)
{

View File

@ -18,47 +18,63 @@
package helpers;
import entities.User;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import entities.*;
import java.util.*;
public class Users {
static List<String> descr_user_1 = new ArrayList<String>() {{
add("File author by default");
add("He doesnt belong to any of the groups");
add("He can review all the changes");
add("Doesnt belong to any group");
add("Can review all the changes");
add("Can perform all actions with comments");
add("The file favorite state is undefined");
add("Can create files from templates using data from the editor");
}};
static List<String> descr_user_2 = new ArrayList<String>() {{
add("He belongs to Group2");
add("He can review only his own changes or the changes made by the users who dont belong to any of the groups");
add("This file is favorite");
add("Belongs to Group2");
add("Can review only his own changes or changes made by users with no group");
add("Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only");
add("This file is marked as favorite");
add("Can create new files from the editor");
}};
static List<String> descr_user_3 = new ArrayList<String>() {{
add("He belongs to Group3");
add("He can review only the changes made by the users from Group2");
add("This file isnt favorite");
add("He cant copy data from the file into the clipboard");
add("He cant download the file");
add("He cant print the file");
add("Belongs to Group3");
add("Can review changes made by Group2 users");
add("Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users");
add("This file isnt marked as favorite");
add("Cant copy data from the file to clipboard");
add("Cant download the file");
add("Cant print the file");
add("Can create new files from the editor");
}};
static List<String> descr_user_0 = new ArrayList<String>() {{
add("The user without a name. The name is requested upon the editor opening");
add("He doesnt belong to any of the groups");
add("He can review all the changes");
add("The name is requested when the editor is opened");
add("Doesnt belong to any group");
add("Can review all the changes");
add("Can perform all actions with comments");
add("The file favorite state is undefined");
add("Can't mention others in comments");
add("Can't create new files from the editor");
}};
private static List<User> users = new ArrayList<User>() {{
add(new User("uid-1", "John Smith", "smith@mail.ru", null, null, null, new ArrayList<String>(), descr_user_1));
add(new User("uid-2", "Mark Pottato", "pottato@mail.ru", "group-2", Arrays.asList("group-2", ""), true, new ArrayList<String>(), descr_user_2));
add(new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru", "group-3", Arrays.asList("group-2"), false, Arrays.asList("copy", "download", "print"), descr_user_3));
add(new User("uid-0", null, null, null, null, null, new ArrayList<String>(), descr_user_0));
add(new User("uid-1", "John Smith", "smith@mail.ru",
null, null, new CommentGroups(),
null, new ArrayList<String>(), descr_user_1, true));
add(new User("uid-2", "Mark Pottato", "pottato@mail.ru",
"group-2", Arrays.asList("group-2", ""), new CommentGroups(null, Arrays.asList("group-2", ""), Arrays.asList("group-2")),
true, new ArrayList<String>(), descr_user_2, false));
add(new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru",
"group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"), Arrays.asList("group-2"), new ArrayList<String>()),
false, Arrays.asList("copy", "download", "print"), descr_user_3, false));
add(new User("uid-0", null, null,
null, null, new CommentGroups(),
null, new ArrayList<String>(), descr_user_0, false));
}};
public static User getUser (String id) {
@ -73,5 +89,18 @@ public class Users {
public static List<User> getAllUsers () {
return users;
}
public static List<Map<String, Object>> getUsersForMentions (String id) {
List<Map<String, Object>> usersData = new ArrayList<>();
for (User user : users) {
if (!user.id.equals(id) && user.name != null && user.email != null) {
Map<String, Object> data = new HashMap<>();
data.put("name", user.name);
data.put("email", user.email);
usersData.add(data);
}
}
return usersData;
}
}

View File

@ -139,6 +139,7 @@
String[] histArray = Model.GetHistory();
String history = histArray[0];
String historyData = histArray[1];
String usersForMentions = (String) request.getAttribute("usersForMentions");
%>
<% if (!history.isEmpty() && !historyData.isEmpty()) { %>
@ -158,6 +159,21 @@
};
<% } %>
<% if (usersForMentions != null) { %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": ${usersForMentions}
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% } %>
var сonnectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -20,10 +20,18 @@ express - Fast, unopinionated, minimalist web framework for node. (https:/
License: MIT
License File: express.license
fast-xml-parser - Validate XML, Parse XML to JS/JSON and vice versa, or parse XML to Nimn rapidly without C/C++ based libraries and no callback. (https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/LICENSE)
License: MIT
License File: fast-xml-parser.license
formidable - A Node.js module for parsing form data, especially file uploads. (https://github.com/node-formidable/formidable/blob/master/LICENSE)
License: MIT
License File: formidable.license
he - a robust HTML entity encoder/decoder written in JavaScript. (https://github.com/mathiasbynens/he/blob/master/LICENSE-MIT.txt)
License: MIT
License File: he.license
jQuery - jQuery is a new kind of JavaScript Library. jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript. NOTE: This package is maintained on behalf of the library owners by the NuGet Community Packages project at https://nugetpackages.codeplex.com/ (https://jquery.org/license/)
License: MIT
License File: jQuery.license

View File

@ -1,26 +1,22 @@
# How to integrate online editors into your own web site on Node.js
## Overview
## Introduction
This example will help you integrate ONLYOFFICE Docs into your web application on Node.js.
To integrate **ONLYOFFICE online editors** into your own website on **Node.js** you need to download and install ONLYOFFICE editors on your local server and use the [Node.js Example](https://api.onlyoffice.com/editors/demopreview) for their integration. We will show you how to run the Node.js example on [Windows OS](#running-the-example-on-windows-os) and [Linux OS](#running-the-example-on-linux-os).
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
Please nore that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
## For Windows
This guide will show you the sequence of actions to integrate the editors successfully.
### Step 1. Install ONLYOFFICE Docs
## Running the example on Windows OS
Download and install ONLYOFFICE Docs (packaged as Document Server).
## Step 1. Download and Install Document Server
See the detailed guide to learn how to [install Document Server for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx).
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
See the detailed guide to learn how to [install Document Server for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_nodejs_example).
## Step 2. Download the Node.js code for the editors integration
### Step 2. Download the Node.js code for the editors integration
Download the [Node.js example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connect the editors to your web site. For that specify the path to the editors installation in the *config/default.json* file:
You need to connect the editors to your website. Specify the path to the editors installation in the *config/default.json* file:
```
"siteUrl": "https://documentserver/"
@ -30,11 +26,11 @@ where the **documentserver** is the name of the server with the ONLYOFFICE Docum
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *\views\editor.ejs* file.
## Step 3. System requirements
### Step 3. Install Node.js environment
Download and install the **node.js** environment which is going to be used to run the Node.js project. Please follow the link at the official website: https://nodejs.org/en/download/, choosing the correct version for your Windows OS (32-bit or 64-bit).
Install the **node.js** environment which is going to be used to run the Node.js project. Please follow the link at the official website: https://nodejs.org/en/download/ choosing the correct version for your Windows OS (32-bit or 64-bit).
## Step 4. Running the Node.js code
### Step 4. Run the Node.js code
We will run the code in Node.js runtime environment and will interact with it using the command line interface (cmd).
@ -64,19 +60,21 @@ We will run the code in Node.js runtime environment and will interact with it us
http://localhost:3000
```
## Step 5. Checking accessibility
### Step 5. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
## Running the example on Linux OS
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Step 1. Download and Install Document Server
## For Linux
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
### Step 1. Install ONLYOFFICE Docs
See the detailed guide to learn how to [install Document Server for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_nodejs_example).
Download and install ONLYOFFICE Docs (packaged as Document Server).
## Step 2. Install the prerequisites and run the web site with the editors
See the detailed guide to learn how to [install Document Server for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx).
### Step 2. Install the prerequisites and run the website with the editors
1. Install **Node.js**:
@ -88,7 +86,7 @@ See the detailed guide to learn how to [install Document Server for Linux](https
sudo apt-get install -y nodejs
```
2. Download the archive with the Node.js example and unpack the archive:
2. Download the archive with the Node.js example and unpack it:
```
wget https://api.onlyoffice.com/app_data/editor/Node.js%20Example.zip
@ -136,6 +134,8 @@ See the detailed guide to learn how to [install Document Server for Linux](https
http://localhost:3000
```
## Step 3. Checking accessibility
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -33,6 +33,7 @@ const mime = require("mime");
const docManager = require("./helpers/docManager");
const documentService = require("./helpers/documentService");
const fileUtility = require("./helpers/fileUtility");
const wopiApp = require("./helpers/wopi/wopiRouting");
const users = require("./helpers/users");
const siteUrl = configServer.get('siteUrl');
const fileChoiceUrl = configServer.has('fileChoiceUrl') ? configServer.get('fileChoiceUrl') : "";
@ -628,6 +629,7 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
docManager.init(storageFolder, req, res);
var fileName = fileUtility.getFileName(req.query.fileName);
var fileExt = req.query.fileExt;
var history = [];
var historyData = [];
@ -638,8 +640,24 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
var name = user.name;
var actionData = req.query.action ? req.query.action : "null";
var templatesImageUrl = docManager.getTemplateImageUrl(fileUtility.getFileType(fileName));
var createUrl = docManager.getCreateUrl(fileUtility.getFileType(fileName), userid, type, lang);
var templates = [
{
"image": templatesImageUrl,
"title": "Blank",
"url": createUrl
},
{
"image": templatesImageUrl,
"title": "With sample content",
"url": createUrl + "&sample=true"
}
];
var userGroup = user.group;
var reviewGroups = user.reviewGroups;
var commentGroups = user.commentGroups;
if (fileExt != null) {
var fileName = docManager.createDemo(!!req.query.sample, fileExt, userid, name); // create demo document of a given extension
@ -651,7 +669,6 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
}
var userAddress = docManager.curUserHostAddress();
var fileName = fileUtility.getFileName(req.query.fileName);
if (!docManager.existsSync(docManager.storagePath(fileName, userAddress))) { // if the file with a given name doesn't exist
throw {
"message": "File not found: " + fileName // display error message
@ -681,6 +698,7 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
for (var i = 1; i <= countVersion; i++) { // get keys to all the file versions
if (i < countVersion) {
var keyPath = docManager.keyPath(fileName, userAddress, i);
if (!fileSystem.existsSync(keyPath)) continue;
keyVersion = "" + fileSystem.readFileSync(keyPath);
} else {
keyVersion = key;
@ -741,7 +759,8 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
key: key,
token: "",
callbackUrl: docManager.getCallback(fileName),
createUrl: docManager.getCreateUrl(fileUtility.getFileType(fileName), userid, type, lang),
createUrl: userid != "uid-0" ? createUrl : null,
templates: user.templates ? templates : null,
isEdit: canEdit && (mode == "edit" || mode == "view" || mode == "filter" || mode == "blockcontent"),
review: canEdit && (mode == "edit" || mode == "review"),
comment: mode != "view" && mode != "fillForms" && mode != "embedded" && mode != "blockcontent",
@ -760,6 +779,7 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
name: name,
userGroup: userGroup,
reviewGroups: JSON.stringify(reviewGroups),
commentGroups: JSON.stringify(commentGroups),
fileChoiceUrl: fileChoiceUrl,
submitForm: submitForm,
plugins: JSON.stringify(plugins),
@ -778,7 +798,8 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
dataMailMergeRecipients: {
fileType: "csv",
url: docManager.getServerUrl(true) + "/csv"
}
},
usersForMentions: user.id != "uid-0" ? users.getUsersForMentions(user.id) : null,
};
if (cfgSignatureEnable) {
@ -805,6 +826,8 @@ app.get("/editor", function (req, res) { // define a handler for editing docume
}
});
wopiApp.registerRoutes(app);
// "Not found" error with 404 status
app.use(function (req, res, next) {
const err = new Error("Not Found");
@ -821,4 +844,4 @@ app.use(function (err, req, res, next) {
});
// save all the functions to the app module to export it later in other files
module.exports = app;
module.exports = app;

View File

@ -13,6 +13,9 @@
"server": {
"port": 3000,
"siteUrl": "https://documentserver/",
"wopi": {
"discovery": "hosting/discovery"
},
"commandUrl": "coauthoring/CommandService.ashx",
"converterUrl": "ConvertService.ashx",
"apiUrl": "web-apps/apps/api/documents/api.js",

View File

@ -1,7 +1,7 @@
{
"server": {
"port": 3000,
"siteUrl": "http://127.0.0.1:8001/",
"siteUrl": "http://127.0.0.1:8000/",
"apiUrl": "web-apps/apps/api/documents/api.js",
"preloaderUrl": "web-apps/apps/api/documents/cache-scripts.html"
}

View File

@ -1,7 +1,7 @@
{
"server": {
"port": 3000,
"siteUrl": "http://127.0.0.1:8001/",
"siteUrl": "http://127.0.0.1:8000/",
"apiUrl": "web-apps/apps/api/documents/api.js",
"preloaderUrl": "web-apps/apps/api/documents/cache-scripts.html"
}

View File

@ -1,7 +1,7 @@
{
"server": {
"port": 80,
"siteUrl": "http://127.0.0.1:8001/",
"siteUrl": "http://127.0.0.1:8000/",
"apiUrl": "web-apps/apps/api/documents/api.js",
"preloaderUrl": "web-apps/apps/api/documents/cache-scripts.html"
}

View File

@ -331,6 +331,20 @@ docManager.getInternalExtension = function (fileType) {
return ".docx"; // the default value is .docx
};
docManager.getTemplateImageUrl = function (fileType) {
let path = docManager.getServerUrl(true);
if (fileType == fileUtility.fileType.word) // for word type
return path + "/images/file_docx.svg";
if (fileType == fileUtility.fileType.cell) // for cell type
return path + "/images/file_xlsx.svg";
if (fileType == fileUtility.fileType.slide) // for slide type
return path + "/images/file_pptx.svg";
return path + "/images/file_docx.svg"; // the default value
}
// get document key
docManager.getKey = function (fileName) {
const userAddress = docManager.curUserHostAddress();
@ -376,11 +390,13 @@ docManager.getHistory = function (fileName, content, keyVersion, version) {
let oldVersion = false;
let contentJson = null;
if (content) { // if content is defined
if (content.changes) { // and there are some modifications in the content
if (content.changes && content.changes.length) { // and there are some modifications in the content
contentJson = content.changes[0]; // write these modifications to the json content
} else {
} else if (content.length){
contentJson = content[0]; // otherwise, write original content to the json content
oldVersion = true; // and note that this is an old version
} else {
content = false;
}
}

View File

@ -18,49 +18,80 @@
var descr_user_1 = [
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
];
var descr_user_2 = [
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
];
var descr_user_3 = [
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
];
var descr_user_0 = [
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
];
var users = [
new User("uid-1", "John Smith", "smith@mail.ru", null, null, null, [], descr_user_1),
new User("uid-2", "Mark Pottato", "pottato@mail.ru", "group-2", ["group-2", ""], true, [], descr_user_2), // own and without group
new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru", "group-3", ["group-2"], false, ["copy", "download", "print"], descr_user_3), // other group only
new User("uid-0", null, null, null, null, null, [], descr_user_0),
new User("uid-1", "John Smith", "smith@mail.ru",
null, null, {},
null, [], descr_user_1, true),
new User("uid-2", "Mark Pottato", "pottato@mail.ru",
"group-2", ["group-2", ""], {
view: "",
edit: ["group-2", ""],
remove: ["group-2"]
},
true, [], descr_user_2, false), // own and without group
new User("uid-3", "Hamish Mitchell", "mitchell@mail.ru",
"group-3", ["group-2"], {
view: ["group-3", "group-2"],
edit: ["group-2"],
remove: []
},
false, ["copy", "download", "print"], descr_user_3, false), // other group only
new User("uid-0", null, null,
null, null, {},
null, [], descr_user_0, false),
];
function User(id, name, email, group, reviewGroups, favorite, deniedPermissions, descriptions) {
function User(id, name, email, group, reviewGroups, commentGroups, favorite, deniedPermissions, descriptions, templates) {
this.id = id;
this.name = name;
this.email = email;
this.group = group;
this.reviewGroups = reviewGroups;
this.commentGroups = commentGroups;
this.favorite = favorite;
this.deniedPermissions = deniedPermissions;
this.descriptions = descriptions;
this.templates = templates;
};
users.getAllUsers = function () {
return users;
};
users.getUser = function (id) {
@ -73,4 +104,14 @@ users.getUser = function (id) {
return result ? result : this[0];
};
module.exports = users;
users.getUsersForMentions = function (id) {
var result = [];
this.forEach(user => {
if (user.id != id && user.name != null && user.email != null) {
result.push({ name: user.name, email: user.email });
}
});
return result;
};
module.exports = users;

View File

@ -0,0 +1,303 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const reqConsts = require('./request');
const docManager = require("../docManager");
const fileUtility = require("../fileUtility");
const lockManager = require("./lockManager");
const utils = require("./utils");
const fileSystem = require("fs");
const mime = require("mime");
const path = require("path");
const users = require("../users");
const actionMapping = {};
actionMapping[reqConsts.requestType.GetFile] = getFile;
actionMapping[reqConsts.requestType.PutFile] = putFile;
actionMapping[reqConsts.requestType.CheckFileInfo] = checkFileInfo;
actionMapping[reqConsts.requestType.UnlockAndRelock] = unlockAndRelock;
actionMapping[reqConsts.requestType.Lock] = lock;
actionMapping[reqConsts.requestType.GetLock] = getLock;
actionMapping[reqConsts.requestType.RefreshLock] = refreshLock;
actionMapping[reqConsts.requestType.Unlock] = unlock;
function parseWopiRequest(req) {
let wopiData = {
requestType: reqConsts.requestType.None,
accessToken: req.query["access_token"],
id: req.params['id']
}
let reqPath = req.path.substring("/wopi/".length)
if (reqPath.startsWith("files")) {
if (reqPath.endsWith("/contents")) {
if (req.method == "GET") {
wopiData.requestType = reqConsts.requestType.GetFile;
} else if (req.method == "POST") {
wopiData.requestType = reqConsts.requestType.PutFile;
}
} else {
if (req.method == "GET") {
wopiData.requestType = reqConsts.requestType.CheckFileInfo;
} else if (req.method == "POST") {
let wopiOverride = req.headers[reqConsts.requestHeaders.RequestType.toLowerCase()];
switch (wopiOverride) {
case "LOCK":
if (req.headers[reqConsts.requestHeaders.OldLock.toLowerCase()]) {
wopiData.requestType = reqConsts.requestType.UnlockAndRelock;
} else {
wopiData.requestType = reqConsts.requestType.Lock;
}
break;
case "GET_LOCK":
wopiData.requestType = reqConsts.requestType.GetLock;
break;
case "REFRESH_LOCK":
wopiData.requestType = reqConsts.requestType.RefreshLock;
break;
case "UNLOCK":
wopiData.requestType = reqConsts.requestType.Unlock;
break;
case "PUT_RELATIVE":
wopiData.requestType = reqConsts.requestType.PutRelativeFile;
break;
case "RENAME_FILE":
wopiData.requestType = reqConsts.requestType.RenameFile;
break;
case "PUT_USER_INFO":
wopiData.requestType = reqConsts.requestType.PutUserInfo;
break;
}
}
}
} else if (reqPath.startsWith("folders")) {
}
return wopiData;
}
function lock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => lock
lockManager.lock(filePath, requestLock);
res.sendStatus(200);
} else if (lockManager.getLock(filePath) == requestLock) {
// lock matches current lock => extend duration
lockManager.lock(filePath, requestLock);
res.sendStatus(200);
} else {
// file locked by someone else => return lock mismatch
let lock = lockManager.getLock(filePath);
returnLockMismatch(res, lock, "File already locked by " + lock)
}
}
function getLock(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
res.setHeader(reqConsts.requestHeaders.lock, lockManager.getLock(filePath));
res.sendStatus(200);
}
function refreshLock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
returnLockMismatch(res, "", "File isn't locked");
} else if (lockManager.getLock(filePath) == requestLock) {
// lock matches current lock => extend duration
lockManager.lock(filePath, requestLock);
res.sendStatus(200);
} else {
// lock mismatch
returnLockMismatch(res, lockManager.getLock(filePath), "Lock mismatch");
}
}
function unlock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
returnLockMismatch(res, "", "File isn't locked");
} else if (lockManager.getLock(filePath) == requestLock) {
// lock matches current lock => unlock
lockManager.unlock(filePath);
res.sendStatus(200);
} else {
// lock mismatch
returnLockMismatch(res, lockManager.getLock(filePath), "Lock mismatch");
}
}
function unlockAndRelock(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let oldLock = req.headers[reqConsts.requestHeaders.oldLock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let filePath = docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(filePath)) {
// file isn't locked => mismatch
returnLockMismatch(res, "", "File isn't locked");
} else if (lockManager.getLock(filePath) == oldLock) {
// lock matches current lock => lock with new key
lockManager.lock(filePath, requestLock);
res.sendStatus(200);
} else {
// lock mismatch
returnLockMismatch(res, lockManager.getLock(filePath), "Lock mismatch");
}
}
function getFile(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let path = docManager.storagePath(wopi.id, userAddress);
res.setHeader("Content-Length", fileSystem.statSync(path).size);
res.setHeader("Content-Type", mime.getType(path));
res.setHeader("Content-Disposition", "attachment; filename*=UTF-8\'\'" + encodeURIComponent(wopi.id));
let filestream = fileSystem.createReadStream(path);
filestream.pipe(res);
}
function putFile(wopi, req, res, userHost) {
let requestLock = req.headers[reqConsts.requestHeaders.Lock.toLowerCase()];
let userAddress = docManager.curUserHostAddress(userHost);
let storagePath = docManager.storagePath(wopi.id, userAddress);
if (!lockManager.hasLock(storagePath)) {
// ToDo: if body length is 0 bytes => handle document creation
// file isn't locked => mismatch
returnLockMismatch(res, "", "File isn't locked");
} else if (lockManager.getLock(storagePath) == requestLock) {
// lock matches current lock => put file
if (req.body) {
var historyPath = docManager.historyPath(wopi.id, userAddress);
if (historyPath == "") {
historyPath = docManager.historyPath(wopi.id, userAddress, true);
docManager.createDirectory(historyPath);
}
var count_version = docManager.countVersion(historyPath);
version = count_version + 1;
res.setHeader(reqConsts.requestHeaders.ItemVersion, version + 1);
var versionPath = docManager.versionPath(wopi.id, userAddress, version);
docManager.createDirectory(versionPath);
var path_prev = path.join(versionPath, "prev" + fileUtility.getFileExtension(wopi.id));
fileSystem.renameSync(docManager.storagePath(wopi.id, userAddress), path_prev);
let filestream = fileSystem.createWriteStream(storagePath);
req.pipe(filestream);
req.on('end', () => {
filestream.close();
res.sendStatus(200);
})
} else {
res.sendStatus(404);
}
} else {
// lock mismatch
returnLockMismatch(res, lockManager.getLock(storagePath), "Lock mismatch");
}
}
function checkFileInfo(wopi, req, res, userHost) {
let userAddress = docManager.curUserHostAddress(userHost);
let historyPath = docManager.historyPath(wopi.id, userAddress);
let version = 1;
if (historyPath != "") {
version = docManager.countVersion(historyPath) + 1;
}
let path = docManager.storagePath(wopi.id, userAddress);
let user = users.getUser(req.query.userid);
let fileInfo = {
"BaseFileName": wopi.id,
"OwnerId": docManager.getFileData(wopi.id, userAddress)[1],
"Size": fileSystem.statSync(path).size,
"UserId": user.id,
"UserFriendlyName": user.name,
"Version": version,
"UserCanWrite": true,
"SupportsGetLock": true,
"SupportsLocks": true,
"SupportsUpdate": true,
};
res.status(200).send(fileInfo);
}
function returnLockMismatch(res, lock, reason) {
res.setHeader(reqConsts.requestHeaders.Lock, lock || "");
if (reason) {
res.setHeader(reqConsts.requestHeaders.LockFailureReason, reason);
}
res.sendStatus(409); // conflict
}
exports.fileRequestHandler = (req, res) => {
let userAddress = null;
if (req.params['id'].includes("@")) {
let split = req.params['id'].split("@");
req.params['id'] = split[0];
userAddress = split[1];
}
let wopiData = parseWopiRequest(req);
if (wopiData.requestType == reqConsts.requestType.None) {
res.status(500).send({ 'title': 'fileHandler', 'method': req.method, 'id': req.params['id'], 'error': "unknown" });
return;
}
let action = actionMapping[wopiData.requestType];
if (!action) {
res.status(501).send({ 'title': 'fileHandler', 'method': req.method, 'id': req.params['id'], 'error': "unsupported" });
return;
}
action(wopiData, req, res);
}

View File

@ -0,0 +1,62 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
var lockDict = {};
function getLockObject(filePath) {
return lockDict[filePath];
}
function clearLockTimeout(lockObject) {
if (lockObject && lockObject.timeout) {
clearTimeout(lockObject.timeout);
}
}
function getLockValue(filePath) {
let lock = getLockObject(filePath);
if (lock) return lock.value;
return "";
}
function hasLock(filePath) {
return !!getLockObject(filePath);
}
function lock(filePath, lockValue) {
let oldLock = getLockObject(filePath);
clearLockTimeout(oldLock);
lockDict[filePath] = {
value: lockValue,
timeout: setTimeout(unlock, 1000 * 60 * 30, filePath) // set lock for 30 minutes
}
}
function unlock(filePath) {
let lock = getLockObject(filePath);
clearLockTimeout(lock);
delete lockDict[filePath];
}
module.exports = {
hasLock: hasLock,
getLock: getLockValue,
lock: lock,
unlock: unlock
}

View File

@ -0,0 +1,66 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const requestType = Object.freeze({
"None": 0,
"CheckFileInfo": 1,
"PutRelativeFile": 2,
"Lock": 3,
"GetLock": 4,
"Unlock": 5,
"RefreshLock": 6,
"UnlockAndRelock": 7,
"ExecuteCobaltRequest": 8,
"DeleteFile": 9,
"ReadSecureStore": 10,
"GetRestrictedLink": 11,
"RevokeRestrictedLink": 12,
"CheckFolderInfo": 13,
"GetFile": 14,
"PutFile": 16,
"EnumerateChildren": 16,
"RenameFile": 17,
"PutUserInfo": 18,
});
const requestHeaders = Object.freeze({
"RequestType": "X-WOPI-Override",
"ItemVersion": "X-WOPI-ItemVersion",
"Lock": "X-WOPI-Lock",
"OldLock": "X-WOPI-OldLock",
"LockFailureReason": "X-WOPI-LockFailureReason",
"LockedByOtherInterface": "X-WOPI-LockedByOtherInterface",
"SuggestedTarget": "X-WOPI-SuggestedTarget",
"RelativeTarget": "X-WOPI-RelativeTarget",
"OverwriteRelativeTarget": "X-WOPI-OverwriteRelativeTarget",
});
module.exports = {
requestType: requestType,
requestHeaders: requestHeaders,
}

View File

@ -0,0 +1,23 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
exports.isValidToken = (req, res, next) => {
if (true) {
return next();
}
}

View File

@ -0,0 +1,115 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const config = require("config");
const configServer = config.get("server");
const siteUrl = configServer.get('siteUrl'); // the path to the editors installation
const syncRequest = require("sync-request");
const xmlParser = require("fast-xml-parser");
const he = require("he");
var cache = null;
function getDiscoveryInfo(maxTry = 1) {
let actions = [];
if (cache) return cache;
try {
let response = syncRequest("GET", siteUrl + configServer.get("wopi.discovery"));
let discovery = xmlParser.parse(response.getBody().toString(), {
attributeNamePrefix: "",
ignoreAttributes: false,
parseAttributeValue: true,
attrValueProcessor: (val, attrName) => he.decode(val, { isAttributeValue: true })
});
for (let app of discovery["wopi-discovery"]["net-zone"].app) {
if (!Array.isArray(app.action)) { app.action = [app.action]; }
for (let action of app.action) {
actions.push({
app: app.name,
favIconUrl: app.favIconUrl,
checkLicense: app.checkLicense == 'true',
name: action.name,
ext: action.ext || "",
progid: action.progid || "",
isDefault: action.default ? true : false,
urlsrc: action.urlsrc,
requires: action.requires || ""
});
}
}
} catch (e) {
if (--maxTry > 0) {
setTimeout(getDiscoveryInfo, 1000, maxTry);
}
return actions;
}
cache = actions;
setTimeout(() => cache = null, 1000 * 60 * 60); // 1 hour
return actions;
}
function getActions(ext) {
let actions = getDiscoveryInfo();
let filtered = [];
for (let action of actions) {
if (action.ext == ext) {
filtered.push(action);
}
}
return filtered;
}
function getAction(ext, name) {
let actions = getDiscoveryInfo();
for (let action of actions) {
if (action.ext == ext && action.name == name) {
return action;
}
}
return null;
}
function getDefaultAction(ext) {
let actions = getDiscoveryInfo();
for (let action of actions) {
if (action.ext == ext && action.isDefault) {
return action;
}
}
return null;
}
function getActionUrl(host, userAddress, action, filename) {
return action.urlsrc.replace(/<.*&>/g, "") + "WOPISrc=" + host + "/wopi/files/" + filename + "@" + userAddress;
}
exports.getDiscoveryInfo = getDiscoveryInfo;
exports.getAction = getAction;
exports.getActions = getActions;
exports.getActionUrl = getActionUrl;
exports.getDefaultAction = getDefaultAction;

View File

@ -0,0 +1,110 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const tokenValidator = require("./tokenValidator");
const filesController = require("./filesController");
const utils = require("./utils");
const docManager = require("../docManager");
const fileUtility = require("../fileUtility");
const config = require('config');
const configServer = config.get('server');
const storageFolder = configServer.get("storageFolder");
const users = require("../users");
exports.registerRoutes = function(app) {
app.get("/wopi", function(req, res) {
utils.getDiscoveryInfo(3);
try {
docManager.init(storageFolder, req, res);
let files = docManager.getStoredFiles();
for (var file of files) {
let ext = fileUtility.getFileExtension(file.name, true);
file.actions = utils.getActions(ext);
file.defaultAction = utils.getDefaultAction(ext);
}
res.render("wopiIndex", {
storedFiles: files,
params: docManager.getCustomParams(),
users: users,
});
} catch (ex) {
console.log(ex);
res.status(500);
res.render("error", { message: "Server error" });
return;
}
});
app.get("/wopi-new", function(req, res) {
var fileExt = req.query.fileExt;
var user = users.getUser(req.query.userid);
if (fileExt != null) {
var fileName = docManager.createDemo(!!req.query.sample, fileExt, user.id, user.name);
var redirectPath = docManager.getServerUrl() + "/wopi-action/" + encodeURIComponent(fileName) + "?action=edit" + docManager.getCustomParams();
res.redirect(redirectPath);
return;
}
});
app.get("/wopi-action/:id", function(req, res) {
try {
docManager.init(storageFolder, req, res);
let action = utils.getAction(fileUtility.getFileExtension(req.params['id'], true), req.query["action"]);
res.render("wopiAction", {
actionUrl: utils.getActionUrl(docManager.getServerUrl(), docManager.curUserHostAddress(), action, req.params['id']),
token: "test",
tokenTtl: Date.now() + 1000 * 60 * 60 * 10,
params: docManager.getCustomParams(),
});
} catch (ex) {
console.log(ex);
res.status(500);
res.render("error", { message: "Server error" });
return;
}
});
app.route('/wopi/files/:id')
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
app.route('/wopi/files/:id/contents')
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
app.route('/wopi/folders/:id')
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
app.route('/wopi/folders/:id/contents')
.all(tokenValidator.isValidToken)
.get(filesController.fileRequestHandler)
.post(filesController.fileRequestHandler);
};

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Amit Kumar Gupta
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,20 @@
Copyright Mathias Bynens <https://mathiasbynens.be/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -594,6 +594,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"fast-xml-parser": {
"version": "3.19.0",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.19.0.tgz",
"integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg=="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@ -758,6 +763,11 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"http-basic": {
"version": "8.1.3",
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",

View File

@ -20,7 +20,9 @@
"debug": "^4.2.0",
"ejs": "^3.1.5",
"express": "^4.17.1",
"fast-xml-parser": "^3.19.0",
"formidable": "^1.2.2",
"he": "^1.2.0",
"jsonwebtoken": "^8.5.1",
"jwa": "^2.0.0",
"log4js": "^6.3.0",

View File

@ -247,7 +247,8 @@ label .checkbox {
width: 192px;
}
.create-panel {
.create-panel,
.links-panel {
float: left;
padding: 16px 0;
}
@ -258,6 +259,12 @@ label .checkbox {
border-bottom: 1px solid #D0D5DA;
}
.links-panel-border {
margin-top: 24px;
width: 100%;
border-top: 1px solid #D0D5DA;
}
#mainProgress {
color: #333333;
display: none;
@ -558,6 +565,15 @@ footer a:hover {
width: 4%;
}
.contentCells-wopi {
width: 16%;
text-align: center;
}
.contentCells-wopi a {
text-decoration: none;
}
.select-user {
color: #444444;
font-family: Open Sans;

View File

@ -23,7 +23,8 @@
"modifyFilter": <%- editor.modifyFilter %>,
"modifyContentControl": <%- editor.modifyContentControl %>,
"review": <%- editor.review %>,
"reviewGroups": <%- editor.reviewGroups %>
"reviewGroups": <%- editor.reviewGroups %>,
"commentGroups": <%- editor.commentGroups %>
}
},
"editorConfig": {
@ -31,7 +32,8 @@
"mode": "<%- editor.mode %>",
"lang": "<%- editor.lang %>",
"callbackUrl": "<%- editor.callbackUrl %>",
"createUrl": "<%- editor.createUrl%>",
"createUrl": <%- JSON.stringify(editor.createUrl) %>,
"templates": <%- JSON.stringify(editor.templates) %>,
"user": {
"group": "<%- editor.userGroup %>",
"id": "<%- editor.userid %>",

View File

@ -132,29 +132,51 @@
docEditor.setMailMergeRecipients(<%- JSON.stringify(dataMailMergeRecipients) %>); // insert recipient data for mail merge into the file
};
var connectEditor = function () {
docEditor = new DocsAPI.DocEditor("iframeEditor", {<%- include("config") %>,
events: {
"onAppReady": onAppReady,
"onDocumentStateChange": onDocumentStateChange,
"onRequestEditRights": onRequestEditRights,
"onError": onError,
"onRequestHistory": onRequestHistory,
"onRequestHistoryData": onRequestHistoryData,
"onRequestHistoryClose": onRequestHistoryClose,
"onOutdatedVersion": onOutdatedVersion,
"onMakeActionLink": onMakeActionLink,
"onMetaChange": onMetaChange,
"onRequestInsertImage": onRequestInsertImage,
"onRequestCompareFile": onRequestCompareFile,
"onRequestMailMergeRecipients": onRequestMailMergeRecipients,
}
var onRequestUsers = function () {
docEditor.setUsers({
"users": <%- JSON.stringify(usersForMentions) %>
});
};
var onRequestSendNotify = function(event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
var events = {
"onAppReady": onAppReady,
"onDocumentStateChange": onDocumentStateChange,
"onRequestEditRights": onRequestEditRights,
"onError": onError,
"onRequestHistory": onRequestHistory,
"onRequestHistoryData": onRequestHistoryData,
"onRequestHistoryClose": onRequestHistoryClose,
"onOutdatedVersion": onOutdatedVersion,
"onMakeActionLink": onMakeActionLink,
"onMetaChange": onMetaChange,
"onRequestInsertImage": onRequestInsertImage,
"onRequestCompareFile": onRequestCompareFile,
"onRequestMailMergeRecipients": onRequestMailMergeRecipients,
};
var config = {<%- include("config") %>, events};
var connectEditor = function () {
addMentions();
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
fixSize();
};
var addMentions = function () {
if (<%- JSON.stringify(usersForMentions) %> != null)
{
events.onRequestUsers = onRequestUsers;
events.onRequestSendNotify = onRequestSendNotify;
}
};
// get the editor sizes
var fixSize = function () {
var wrapEl = document.getElementsByClassName("form");

View File

@ -131,6 +131,10 @@
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="/wopi" class="">Go to WOPI page</a>
</div>
</div>
</div>
</td>

View File

@ -0,0 +1,77 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width" />
<!--
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
-->
<title>ONLYOFFICE Document Editors</title>
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<style type="text/css">
body {
margin: 0;
padding: 0;
overflow: hidden;
-ms-content-zooming: none;
}
#office_frame {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
border: none;
display: block;
}
</style>
</head>
<body>
<form id="office_form" name="office_form" target="office_frame" action="<%= actionUrl %>" method="post">
<input name="access_token" value="<%= token %><%= params %>" type="hidden" />
<input name="access_token_ttl" value="<%= tokenTtl %>" type="hidden" />
</form>
<span id="frameholder"></span>
<script type="text/javascript">
var frameholder = document.getElementById('frameholder');
var office_frame = document.createElement('iframe');
office_frame.name = 'office_frame';
office_frame.id = 'office_frame';
office_frame.title = 'Office Frame';
office_frame.setAttribute('allowfullscreen', 'true');
office_frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-popups allow-top-navigation allow-popups-to-escape-sandbox');
frameholder.appendChild(office_frame);
document.getElementById('office_form').submit();
</script>
</body>
</html>

View File

@ -0,0 +1,239 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width" />
<!--
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
-->
<title>ONLYOFFICE Document Editors</title>
<link href="images/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/jquery-ui.css" />
</head>
<body>
<header>
<div class="center">
<a href="">
<img src="images/logo.svg" alt="ONLYOFFICE" />
</a>
</div>
</header>
<div class="center main">
<table class="table-main">
<tbody>
<tr>
<td class="left-panel section">
<div class="help-block">
<span>Create new</span>
<div class="clearFix">
<div class="create-panel clearFix">
<ul class="try-editor-list clearFix">
<li>
<a class="try-editor word reload-page" target="_blank" href="/wopi-new?fileExt=docx<%= params %>" title="Create new document">Document</a>
</li>
<li>
<a class="try-editor cell reload-page" target="_blank" href="/wopi-new?fileExt=xlsx<%= params %>" title="Create new spreadsheet">Spreadsheet</a>
</li>
<li>
<a class="try-editor slide reload-page" target="_blank" href="/wopi-new?fileExt=pptx<%= params %>" title="Create new presentation">Presentation</a>
</li>
</ul>
<label class="create-sample">
<input id="createSample" type="checkbox" class="checkbox" />With sample content
</label>
</div>
</div>
<table class="user-block-table" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="middle">
<span class="select-user">Username</span>
<img class="info" data-id="user" data-tooltip="You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.
</br>
<% users.forEach(user => { %>
<b><%= user.name == null ? 'Anonymous' : user.name %></b>
<ul>
<% user.descriptions.forEach(description => { %>
<li><%= description %></li>
<% }) %>
</ul>
<% }) %>"
src="images/info.svg" />
<select class="select-user" id="user">
<% users.forEach(user => { %>
<option value="<%= user.id %>"><%= user.name == null ? "Anonymous" : user.name %></option>
<% }) %>
</select>
</td>
</tr>
<tr>
<td valign="middle">
<span class="select-user">Language</span>
<img class="info" data-id="language" data-tooltip="Choose the language for ONLYOFFICE editors interface" src="images/info.svg" />
<select class="select-user" id="language">
<option value="en">English</option>
<option value="be">Belarusian</option>
<option value="bg">Bulgarian</option>
<option value="ca">Catalan</option>
<option value="zh">Chinese</option>
<option value="cs">Czech</option>
<option value="da">Danish</option>
<option value="nl">Dutch</option>
<option value="fi">Finnish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="hu">Hungarian</option>
<option value="id">Indonesian</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="ko">Korean</option>
<option value="lv">Latvian</option>
<option value="lo">Lao</option>
<option value="nb">Norwegian</option>
<option value="pl">Polish</option>
<option value="pt">Portuguese</option>
<option value="ro">Romanian</option>
<option value="ru">Russian</option>
<option value="sk">Slovak</option>
<option value="sl">Slovenian</option>
<option value="sv">Swedish</option>
<option value="es">Spanish</option>
<option value="tr">Turkish</option>
<option value="uk">Ukrainian</option>
<option value="vi">Vietnamese</option>
</select>
</td>
</tr>
</tbody>
</table>
<div class="links-panel links-panel-border clearFix">
<a href="/" class="">Go to Index page</a>
</div>
</div>
</td>
<td class="section">
<div class="main-panel">
<% if (storedFiles.length <= 0)
{ %>
<span class="portal-name">ONLYOFFICE Document Editors Welcome!</span>
<span class="portal-descr">
Get started with a demo-sample of ONLYOFFICE Document Editors, the first html5-based editors.
<br /> You may upload your own documents for testing using the "<b>Upload file</b>" button and <b>selecting</b> the necessary files on your PC.
</span>
<%} else
{ %>
<div class="stored-list">
<span class="header-list">Your documents</span>
<table class="tableHeader" cellspacing="0" cellpadding="0" width="100%">
<thead>
<tr>
<td class="tableHeaderCell tableHeaderCellFileName">Filename</td>
<td class="tableHeaderCell tableHeaderCellEditors contentCells-shift"></td>
<td class="tableHeaderCell tableHeaderCellViewers">WOPI Actions</td>
<td class="tableHeaderCell tableHeaderCellDownload">Download</td>
<td class="tableHeaderCell tableHeaderCellRemove">Remove</td>
</tr>
</thead>
</table>
<div class="scroll-table-body">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<% for (var i = 0; i < storedFiles.length; i++) { %>
<tr class="tableRow" title="<%= storedFiles[i].name %> [<%= storedFiles[i].version %>]">
<td class="contentCells">
<% if (storedFiles[i].defaultAction) { %>
<a class="stored-edit <%= storedFiles[i].documentType %>" href="wopi-action/<%= encodeURIComponent(storedFiles[i].name) %>?action=<%= storedFiles[i].defaultAction.name %><%= params %>">
<%} else { %>
<a class="stored-edit <%= storedFiles[i].documentType %>" href="#">
<% } %>
<span title="<%= storedFiles[i].name %> [<%= storedFiles[i].version %>]"><%= storedFiles[i].name %></span>
</a>
</td>
<% if (storedFiles[i].actions && storedFiles[i].actions.length > 0) { %>
<td class="contentCells contentCells-wopi contentCells-shift">
<% for (var j = 0; j < storedFiles[i].actions.length; j++) { %>
<a href="wopi-action/<%= encodeURIComponent(storedFiles[i].name) %>?action=<%= storedFiles[i].actions[j].name %><%= params %>" target="_blank">
<% if (storedFiles[i].actions[j].name == "edit") { %>
<img src="images/fill-forms-24.png" alt="<%= storedFiles[i].actions[j].name %>" title="<%= storedFiles[i].actions[j].name %>" />
<%} else { %>
<img src="images/desktop-24.png" alt="<%= storedFiles[i].actions[j].name %>" title="<%= storedFiles[i].actions[j].name %>" />
<% } %>
</a>
<% } %>
</td>
<% } %>
<td class="contentCells contentCells-icon contentCells-shift">
<a href="wopi/files/<%= encodeURIComponent(storedFiles[i].name) %>/contents">
<img class="icon-download" src="images/download-24.png" alt="Download" title="Download" /></a>
</td>
<td class="contentCells contentCells-icon contentCells-shift">
<a class="delete-file" data="<%= encodeURIComponent(storedFiles[i].name) %>">
<img class="icon-delete" src="images/delete-24.png" alt="Delete" title="Delete" /></a>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
<% } %>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<footer>
<div class="center">
<table>
<tbody>
<tr>
<td>
<a href="http://api.onlyoffice.com/editors/howitworks" target="_blank">API Documentation</a>
</td>
<td>
<a href="mailto:sales@onlyoffice.com">Submit your request</a>
</td>
<td class="copy">
&copy; Ascensio Systems SIA 2021. All rights reserved.
</td>
</tr>
</tbody>
</table>
</div>
</footer>
<script type="text/javascript" src="javascripts/jquery-1.8.2.js"></script>
<script type="text/javascript" src="javascripts/jquery-ui.js"></script>
<script type="text/javascript" src="javascripts/jquery.blockUI.js"></script>
<script type="text/javascript" src="javascripts/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="javascripts/jquery.fileupload.js"></script>
<script type="text/javascript" src="javascripts/jquery.dropdownToggle.js"></script>
<script type="text/javascript" src="javascripts/jscript.js"></script>
</body>
</html>

View File

@ -1,26 +1,22 @@
# How to integrate online editors into your own web site on PHP
## Overview
## Introduction
This example will help you integrate ONLYOFFICE Docs into your web application written in PHP.
To integrate **ONLYOFFICE online editors** into your own website on **PHP** you need to download and install ONLYOFFICE editors on your local server and use the [PHP Example](https://api.onlyoffice.com/editors/demopreview) for their integration. We will show you how to run the PHP example on [Windows OS](#running-the-example-on-windows-os) and [Linux OS](#running-the-example-on-linux-os).
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
## For Windows
This guide will show you the sequence of actions to integrate the editors successfully.
### Step 1. Install ONLYOFFICE Docs
## Running the example on Windows OS
## Step 1. Download and Install Document Server
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to [install Document Server for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_php_example).
## Step 2. Download the PHP code for the editors integration
### Step 2. Download the PHP code
Download the [PHP example](https://api.onlyoffice.com/editors/demopreview) from our site.
You need to connect the editors to your web site. For that specify the path to the editors installation in the *config.php* file:
You need to connect the editors to your website. Specify the path to the editors installation in the *config.php* file:
```
$GLOBALS['DOC_SERV_SITE_URL'] = "https://documentserver/";
@ -30,15 +26,15 @@ where the **documentserver** is the name of the server with the ONLYOFFICE Docum
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) it the *doceditor.php* file.
## Step 3. Install the prerequisites
### Step 3. Install the prerequisites
You can use any web server capable of runnig PHP code to run the sample. We will demonstrate how to run the PHP sample using the **Internet Information Services (IIS)** web server. To set up and configure PHP on IIS, **PHP Manager for IIS** will be used.
You can use any web server capable of runnig PHP code to run the example. We will demonstrate how to run the PHP example using the **Internet Information Services (IIS)** web server. To set up and configure PHP on IIS, **PHP Manager for IIS** will be used.
* **IIS: version 7** or later (refer to [Microsoft official website](https://www.iis.net/learn/application-frameworks/scenario-build-a-php-website-on-iis/configuring-step-1-install-iis-and-php) to learn how to install **IIS**);
* **PHP** (download it from the [http://php.net](https://php.net/downloads.php) site);
* **PHP Manager for IIS** (download it from the [Microsoft open source site](https://phpmanager.codeplex.com/releases/view/69115)).
## Step 4. IIS configuration
### Step 4. IIS configuration
1. **PHP Manager for IIS** configuration.
@ -81,9 +77,9 @@ You can use any web server capable of runnig PHP code to run the sample. We will
After IIS manager configuration is complete, everything is ready for running the **PHP** example.
## Step 5. Running your web site with the editors
### Step 5. Run your website with the editors
1. Add your web site in the IIS Manager.
1. Add your website in the IIS Manager.
On the **Connections** panel right-click the **Sites** node in the tree, then click **Add Website**.
@ -97,25 +93,27 @@ You can use any web server capable of runnig PHP code to run the sample. We will
![php-add](screenshots/php-add.png)
3. Browse your web site with the IIS manager:
3. Browse your website with the IIS manager:
Right-click the site -> **Manage Website** -> **Browse**
![browse](screenshots/browse.png)
## Step 6. Checking accessibility
### Step 6. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
## Running the example on Linux OS
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
## Step 1. Download and Install Document Server
## For Linux
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
### Step 1. Install ONLYOFFICE Docs
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to [install Document Server for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_php_example).
## Step 2. Install the prerequisites and run the web site with the editors
### Step 2. Install the prerequisites and run the website with the editors
1. Install **Apache** and **PHP**:
@ -175,8 +173,8 @@ See the detailed guide to learn how to [install Document Server for Linux](https
http://localhost/PHP%20Example/
```
## Step 3. Checking accessibility
### Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -171,6 +171,17 @@ function getInternalExtension($filename) {
return "";
}
// get image url for templates
function getTemplateImageUrl($filename) {
$ext = strtolower('.' . pathinfo($filename, PATHINFO_EXTENSION));
$path = serverPath(true) . "/css/images/";
if (in_array($ext, $GLOBALS['ExtsDocument'])) return $path . "file_docx.svg"; // for text document extensions
if (in_array($ext, $GLOBALS['ExtsSpreadsheet'])) return $path . "file_xlsx.svg"; // for spreadsheet extensions
if (in_array($ext, $GLOBALS['ExtsPresentation'])) return $path . "file_pptx.svg"; // for presentation extensions
return $path . "file_docx.svg";
}
// get the document type
function getDocumentType($filename) {
$ext = strtolower('.' . pathinfo($filename, PATHINFO_EXTENSION));

View File

@ -62,6 +62,21 @@
$mode = $canEdit && $editorsMode != "view" ? "edit" : "view"; // define if the editing mode is edit or view
$type = empty($_GET["type"]) ? "desktop" : $_GET["type"];
$templatesImageUrl = getTemplateImageUrl($filename); // templates image url in the "From Template" section
$createUrl = getCreateUrl($filename, $user->id, $type);
$templates = array(
array (
"image" => $templatesImageUrl,
"title" => "Blank",
"url" => $createUrl
),
array (
"image" => $templatesImageUrl,
"title" => "With sample content",
"url" => $createUrl . "&sample=true"
)
);
// specify the document config
$config = [
"type" => $type,
@ -86,7 +101,8 @@
"modifyFilter" => $editorsMode != "filter",
"modifyContentControl" => $editorsMode != "blockcontent",
"review" => $canEdit && ($editorsMode == "edit" || $editorsMode == "review"),
"reviewGroups" => $user->reviewGroups
"reviewGroups" => $user->reviewGroups,
"commentGroups" => $user->commentGroups
]
],
"editorConfig" => [
@ -94,7 +110,8 @@
"mode" => $mode,
"lang" => empty($_COOKIE["ulang"]) ? "en" : $_COOKIE["ulang"],
"callbackUrl" => getCallbackUrl($filename), // absolute URL to the document storage service
"createUrl" => getCreateUrl($filename, $user->id, $type),
"createUrl" => $user->id != "uid-0" ? $createUrl : null,
"templates" => $user->templates ? $templates : null,
"user" => [ // the user currently viewing or editing the document
"id" => $user->id,
"name" => $user->name,
@ -135,6 +152,9 @@
"fileType" =>"csv",
"url" => serverPath(true) . "/webeditor-ajax.php?type=csv"
];
// users data for mentions
$usersForMentions = $user->id != "uid-0" ? getUsersForMentions($user->id) : null;
// check if the secret key to generate token exists
if (isJwtEnabled()) {
@ -174,10 +194,10 @@
function getCreateUrl($fileName, $uid, $type) {
$ext = trim(getInternalExtension($fileName),'.');
return serverPath(false) . '/'
. "doceditor.php"
. "?fileExt=" . $ext
. "&user=" . $uid
. "&type=" . $type;
. "doceditor.php"
. "?fileExt=" . $ext
. "&user=" . $uid
. "&type=" . $type;
}
function getDownloadUrl($fileName) {
@ -228,10 +248,10 @@
$changes = json_decode(file_get_contents(getVersionDir($histDir, $i - 1) . DIRECTORY_SEPARATOR . "changes.json"), true); // get the path to the changes.json file
$change = $changes["changes"][0];
$obj["changes"] = $changes["changes"]; // write information about changes to the object
$obj["changes"] = $change ? $changes["changes"][0] : null; // write information about changes to the object
$obj["serverVersion"] = $changes["serverVersion"];
$obj["created"] = $change["created"];
$obj["user"] = $change["user"];
$obj["created"] = $change ? $change["created"] : null;
$obj["user"] = $change ? $change["user"] : null;
$prev = $histData[$i - 2]; // get the history data from the previous file version
$dataObj["previous"] = [ // write information about previous file version to the data object
@ -441,6 +461,21 @@
};
<?php endif; ?>
<?php if ($usersForMentions != null): ?>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": <?php echo json_encode($usersForMentions) ?>
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<?php endif; ?>
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};

View File

@ -18,53 +18,80 @@
*/
class User {
function __construct($id, $name, $email, $group, $reviewGroups, $favorite, $deniedPermissions, $descriptions)
function __construct($id, $name, $email, $group, $reviewGroups, $commentGroups, $favorite, $deniedPermissions, $descriptions, $templates)
{
$this->id = $id;
$this->name = $name;
$this->email = $email;
$this->group = $group;
$this->reviewGroups = $reviewGroups;
$this->commentGroups = $commentGroups;
$this->favorite = $favorite;
$this->deniedPermissions = $deniedPermissions;
$this->descriptions = $descriptions;
$this->templates = $templates;
}
}
$descr_user_1 = [
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
];
$descr_user_2 = [
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
];
$descr_user_3 = [
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
];
$descr_user_0 = [
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
];
$users = [
new User("uid-1", "John Smith", "smith@mial.ru", null, null, null, [], $descr_user_1),
new User("uid-2", "Mark Pottato", "pottato@mial.ru", "group-2", ["group-2", ""], true, [], $descr_user_2),
new User("uid-3", "Hamish Mitchell", "mitchell@mial.ru", "group-3", ["group-2"], false, ["copy", "download", "print"], $descr_user_3),
new User("uid-0", null, null, null, null, null, [], $descr_user_0)
new User("uid-1", "John Smith", "smith@mial.ru",
null, null, [],
null, [], $descr_user_1, true),
new User("uid-2", "Mark Pottato", "pottato@mial.ru",
"group-2", ["group-2", ""], [
"view" => "",
"edit" => ["group-2", ""],
"remove" => ["group-2"]
],
true, [], $descr_user_2, false),
new User("uid-3", "Hamish Mitchell", "mitchell@mial.ru",
"group-3", ["group-2"], [
"view" => ["group-3", "group-2"],
"edit" => ["group-2"],
"remove" => []
],
false, ["copy", "download", "print"], $descr_user_3, false),
new User("uid-0", null, null,
null, null, [],
null, [], $descr_user_0, false)
];
function getAllUsers() {
@ -83,4 +110,17 @@ function getUser($id) {
return $users[0];
}
?>
function getUsersForMentions($id) {
global $users;
$usersData = [];
foreach ($users as $user) {
if ($user->id != $id && $user->name != null && $user->email != null) {
array_push($usersData,[
"name" => $user->name,
"email" => $user->email
]);
}
}
return $usersData;
}
?>

View File

@ -1,24 +1,20 @@
# How to integrate online editors into your own web site on Python
## Overview
## Introduction
This example will help you integrate ONLYOFFICE Docs into your web application written in Python.
To integrate **ONLYOFFICE online editors** into your own web site on **Python** you need to download and install ONLYOFFICE editors on your local server and use the [Python Example](https://api.onlyoffice.com/editors/demopreview) for their integration. We will show how to run the Python example on Linux OS.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
## Step 1. Install ONLYOFFICE Docs
This guide will show you the sequence of actions to integrate the editors successfully.
## Step 1. Download and Install Document Server
First, download [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
Download and install ONLYOFFICE Docs (packaged as Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_python_example), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_python_example), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx?from=api_python_example).
## Step 2. Install the prerequisites and run the web site with the editors
## Step 2. Install the prerequisites and run the website with the editors
1. Python comes preinstalled on most Linux distributions, and is available as a package on all others. Python 3.9 is required. Please proceed to [official documentation](https://docs.python.org/3/using/unix.html) if you have any troubles.
2. Download the archive with the Python example and unpack the archive:
2. Download the archive with the Python example and unpack it:
```
wget "https://api.onlyoffice.com/app_data/editor/Python%20Example.zip"
@ -71,8 +67,8 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
http://localhost
```
## Step 3. Checking accessibility
## Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **exampleserver** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -99,6 +99,17 @@ def getInternalExtension(fileType):
return mapping.get(fileType, '.docx') # the default file type is .docx
# get image url for templates
def getTemplateImageUrl(fileType, request):
path = getServerUrl(True, request) + '/static/images/'
mapping = {
'word': path + 'file_docx.svg',
'cell': path + 'file_xlsx.svg',
'slide': path + 'file_pptx.svg'
}
return mapping.get(fileType, path + 'file_docx.svg') # the default file type
# get file name with an index if such a file name already exists
def getCorrectName(filename, req):
basename = fileUtils.getFileNameWithoutExt(filename)

View File

@ -194,10 +194,10 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, req):
changes = json.loads(readFile(getChangesHistoryPath(prevVerDir))) # get the path to the changes.json file
change = changes['changes'][0]
obj['changes'] = changes['changes'] # write information about changes to the object
obj['changes'] = changes['changes'] if change else None # write information about changes to the object
obj['serverVersion'] = changes['serverVersion']
obj['created'] = change['created']
obj['user'] = change['user']
obj['created'] = change['created'] if change else None
obj['user'] = change['user'] if change else None
prev = histData[str(i - 2)] # get the history data from the previous file version
prevInfo = { # write key and url information about previous file version

View File

@ -27,54 +27,85 @@
from urllib.parse import unquote
class User:
def __init__(self, id, name, email, group, reviewGroups, favorite, deniedPermissions, descriptions):
def __init__(self, id, name, email, group, reviewGroups, commentGroups, favorite, deniedPermissions, descriptions, templates):
self.id = id
self.name = name
self.email = email
self.group = group
self.reviewGroups = reviewGroups
self.commentGroups = commentGroups
self.favorite = favorite
self.deniedPermissions = deniedPermissions
self.descriptions = descriptions
self.templates = templates
descr_user_1 = [
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
]
descr_user_2 = [
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
]
descr_user_3 = [
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
]
descr_user_0 = [
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
]
USERS = [
User('uid-1', 'John Smith', 'smith@mail.ru', None, None, None, [], descr_user_1),
User('uid-2', 'Mark Pottato', 'pottato@mail.ru', 'group-2', ['group-2', ''], True, [], descr_user_2),
User('uid-3', 'Hamish Mitchell', 'mitchell@mail.ru', 'group-3', ['group-2'], False, ["copy", "download", "print"], descr_user_3),
User('uid-0', None, None, None, None, None, [], descr_user_0)
User('uid-1', 'John Smith', 'smith@mail.ru',
None, None, {},
None, [], descr_user_1, True),
User('uid-2', 'Mark Pottato', 'pottato@mail.ru',
'group-2', ['group-2', ''], {
'view': "",
'edit': ["group-2", ""],
'remove': ["group-2"]
},
True, [], descr_user_2, False),
User('uid-3', 'Hamish Mitchell', 'mitchell@mail.ru',
'group-3', ['group-2'], {
'view': ["group-3", "group-2"],
'edit': ["group-2"],
'remove': []
},
False, ["copy", "download", "print"], descr_user_3, False),
User('uid-0', None, None,
None, None, {},
None, [], descr_user_0, False)
]
DEFAULT_USER = USERS[0]
# get all users
def getAllUsers():
return USERS
# get user information from the request
def getUserFromReq(req):
uid = req.COOKIES.get('uid')
@ -84,3 +115,11 @@ def getUserFromReq(req):
return user
return DEFAULT_USER
# get users data for mentions
def getUsersForMentions(uid):
usersData = []
for user in USERS:
if(user.id != uid and user.name != None and user.email != None):
usersData.append({'name':user.name, 'email':user.email})
return usersData

View File

@ -141,6 +141,21 @@ def edit(request):
actionData = request.GET.get('actionLink') # get the action data that will be scrolled to (comment or bookmark)
actionLink = json.loads(actionData) if actionData else None
templatesImageUrl = docManager.getTemplateImageUrl(fileType, request) # templates image url in the "From Template" section
createUrl = docManager.getCreateUrl(edType, request)
templates = [
{
'image': templatesImageUrl,
'title': 'Blank',
'url': createUrl
},
{
'image': templatesImageUrl,
'title': 'With sample content',
'url': createUrl + '&sample=true'
}
]
if (meta): # if the document meta data exists,
infObj = { # write author and creation time parameters to the information object
'owner': meta['uname'],
@ -172,7 +187,8 @@ def edit(request):
'modifyFilter': edMode != 'filter',
'modifyContentControl': edMode != "blockcontent",
'review': canEdit & ((edMode == 'edit') | (edMode == 'review')),
'reviewGroups': user.reviewGroups
'reviewGroups': user.reviewGroups,
'commentGroups': user.commentGroups
}
},
'editorConfig': {
@ -180,7 +196,8 @@ def edit(request):
'mode': mode,
'lang': lang,
'callbackUrl': docManager.getCallbackUrl(filename, request), # absolute URL to the document storage service
'createUrl': docManager.getCreateUrl(edType, request),
'createUrl' : createUrl if user.id !='uid-0' else None,
'templates' : templates if user.templates else None,
'user': { # the user currently viewing or editing the document
'id': user.id,
'name': user.name,
@ -222,6 +239,9 @@ def edit(request):
'url': docManager.getServerUrl(True, request) + 'csv'
}
# users data for mentions
usersForMentions = users.getUsersForMentions(user.id)
if jwtManager.isEnabled(): # if the secret key to generate token exists
edConfig['token'] = jwtManager.encode(edConfig) # encode the edConfig object into a token
dataInsertImage['token'] = jwtManager.encode(dataInsertImage) # encode the dataInsertImage object into a token
@ -238,7 +258,8 @@ def edit(request):
'apiUrl': config.DOC_SERV_SITE_URL + config.DOC_SERV_API_URL, # the absolute URL to the api
'dataInsertImage': json.dumps(dataInsertImage)[1 : len(json.dumps(dataInsertImage)) - 1], # the image which will be inserted into the document
'dataCompareFile': dataCompareFile, # document which will be compared with the current document
'dataMailMergeRecipients': json.dumps(dataMailMergeRecipients) # recipient data for mail merging
'dataMailMergeRecipients': json.dumps(dataMailMergeRecipients), # recipient data for mail merging
'usersForMentions': json.dumps(usersForMentions) if user.id !='uid-0' else None
}
return render(request, 'editor.html', context) # execute the "editor.html" template with context data

View File

@ -171,6 +171,23 @@
{% endif %}
{% if usersForMentions %}
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": {{ usersForMentions | safe }}
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
{% endif %}
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
fixSize();

View File

@ -1,20 +1,16 @@
# How to integrate online editors into your own web site on Ruby
## Overview
## Introduction
This example will help you integrate ONLYOFFICE Docs into your web application written on Ruby.
To integrate **ONLYOFFICE online editors** into your own website on **Ruby** you need to download and install ONLYOFFICE editors on your local server and use the [Ruby Example](https://api.onlyoffice.com/editors/demopreview) for their integration. We will show how to run the Ruby example on Linux OS.
It is aimed at testing the editors. Please, do not use it for production without proper modifications.
Please note that the integration examples are used to demonstrate document editors functions and the ways to connect **Document Server** to your own application. **DO NOT USE** these examples on your own server without **PROPER CODE MODIFICATIONS**!
## Step 1. Install ONLYOFFICE Docs
This guide will show you the sequence of actions to integrate the editors successfully.
Download and install ONLYOFFICE Docs (packaged as Document Server).
## Step 1. Download and Install Document Server
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx).
First, download the [**ONLYOFFICE Editors**](https://api.onlyoffice.com/editors/demopreview) (the ONLYOFFICE Document Server).
See the detailed guide to learn how to install Document Server [for Windows](https://helpcenter.onlyoffice.com/installation/docs-developer-install-windows.aspx?from=api_ruby_example), [for Linux](https://helpcenter.onlyoffice.com/installation/docs-developer-install-ubuntu.aspx?from=api_ruby_example), or [for Docker](https://helpcenter.onlyoffice.com/server/developer-edition/docker/docker-installation.aspx?from=api_ruby_example).
## Step 2. Install the prerequisites and run the web site with the editors
## Step 2. Install the prerequisites and run the website with the editors
1. Install **Ruby Version Manager (RVM)** and the latest stable **Ruby** version:
@ -76,8 +72,8 @@ See the detailed guide to learn how to install Document Server [for Windows](htt
If you want to experiment with the editor configuration, modify the [parameters](https://api.onlyoffice.com/editors/advanced) in the *views\home\editor.html.erb* file.
## Step 3. Checking accessibility
## Step 3. Check accessibility
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files. And you must also make sure that the Document Server in its turn has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.
In case the example and Document Server are installed on different computers, make sure that your server with the example installed has access to the Document Server with the address which you specify instead of **documentserver** in the configuration files.
If you integrated the editors successfully the result should look like the [demo preview](https://api.onlyoffice.com/editors/demopreview#DemoPreview) on our site.
Make sure that the Document Server has access to the server with the example installed with the address which you specify instead of **example.com** in the configuration files.

View File

@ -276,6 +276,23 @@ class DocumentHelper
ext
end
# get image url for templates
def get_template_image_url(file_type)
path = get_server_url(true) + "/assets/"
case file_type
when 'word' # for word type
full_path = path + 'file_docx.svg'
when 'cell' # .xlsx for cell type
full_path = path + 'file_xlsx.svg'
when 'slide' # .pptx for slide type
full_path = path + 'file_pptx.svg'
else
full_path = path + 'file_docx.svg' # the default value is .docx
end
full_path
end
# get files information
def get_files_info(file_id)
result = [];

View File

@ -84,6 +84,19 @@ class FileModel
canEdit = DocumentHelper.edited_exts.include?(file_ext) # check if the document can be edited
submitForm = canEdit && (editorsmode.eql?("edit") || editorsmode.eql?("fillForms")) # the Submit form button state
mode = canEdit && !editorsmode.eql?("view") ? "edit" : "view"
templatesImageUrl = DocumentHelper.get_template_image_url(document_type) # templates image url in the "From Template" section
templates = [
{
:image => templatesImageUrl,
:title => "Blank",
:url => create_url
},
{
:image => templatesImageUrl,
:title => "With sample content",
:url => create_url + "&sample=true"
}
]
config = {
:type => type(),
@ -108,7 +121,8 @@ class FileModel
:modifyFilter => !editorsmode.eql?("filter"),
:modifyContentControl => !editorsmode.eql?("blockcontent"),
:review => canEdit && (editorsmode.eql?("edit") || editorsmode.eql?("review")),
:reviewGroups => @user.reviewGroups
:reviewGroups => @user.reviewGroups,
:commentGroups => @user.commentGroups
}
},
:editorConfig => {
@ -116,7 +130,8 @@ class FileModel
:mode => mode,
:lang => @lang ? @lang : "en",
:callbackUrl => callback_url, # absolute URL to the document storage service
:createUrl => create_url,
:createUrl => !@user.id.eql?("uid-0") ? create_url : nil,
:templates => @user.templates ? templates : nil,
:user => { # the user currently viewing or editing the document
:id => @user.id,
:name => @user.name,
@ -193,6 +208,7 @@ class FileModel
if (i > 1) # check if the version number is greater than 1
changes = nil
change = nil
File.open(File.join(DocumentHelper.version_dir(hist_dir, i - 1), "changes.json"), 'r') do |file| # get the path to the changes.json file
changes = JSON.parse(file.read()) # and parse its content
end
@ -200,10 +216,10 @@ class FileModel
change = changes["changes"][0]
# write information about changes to the object
obj["changes"] = changes["changes"]
obj["changes"] = change ? changes["changes"] : nil
obj["serverVersion"] = changes["serverVersion"]
obj["created"] = change["created"]
obj["user"] = change["user"]
obj["created"] = change ? change["created"] : nil
obj["user"] = change ? change["user"] : nil
prev = histData[(i - 2).to_s] # get the history data from the previous file version
dataObj["previous"] = { # write key and url information about previous file version
@ -278,4 +294,9 @@ class FileModel
return dataMailMergeRecipients
end
# get users data for mentions
def get_users_mentions
return !@user.id.eql?("uid-0") ? Users.get_users_for_mentions(@user.id) : nil
end
end

View File

@ -15,55 +15,82 @@
#
class User
attr_accessor :id, :name, :email, :group, :reviewGroups, :favorite, :deniedPermissions, :descriptions
attr_accessor :id, :name, :email, :group, :reviewGroups, :commentGroups, :favorite, :deniedPermissions, :descriptions, :templates
def initialize (id, name, email, group, reviewGroups, favorite, deniedPermissions, descriptions)
def initialize (id, name, email, group, reviewGroups, commentGroups, favorite, deniedPermissions, descriptions, templates)
@id = id
@name = name
@email = email
@group = group
@reviewGroups = reviewGroups
@commentGroups = commentGroups
@favorite = favorite
@deniedPermissions = deniedPermissions
@descriptions = descriptions
@templates = templates
end
end
class Users
@@descr_user_1 = [
"File author by default",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can create files from templates using data from the editor"
];
@@descr_user_2 = [
"He belongs to Group2",
"He can review only his own changes or the changes made by the users who dont belong to any of the groups",
"This file is favorite"
"Belongs to Group2",
"Can review only his own changes or changes made by users with no group",
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
"This file is marked as favorite",
"Can create new files from the editor"
];
@@descr_user_3 = [
"He belongs to Group3",
"He can review only the changes made by the users from Group2",
"This file isnt favorite",
"He cant copy data from the file into the clipboard",
"He cant download the file",
"He cant print the file"
"Belongs to Group3",
"Can review changes made by Group2 users",
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
"This file isnt marked as favorite",
"Cant copy data from the file to clipboard",
"Cant download the file",
"Cant print the file",
"Can create new files from the editor"
];
@@descr_user_0 = [
"The user without a name. The name is requested upon the editor opening",
"He doesnt belong to any of the groups",
"He can review all the changes",
"The file favorite state is undefined"
"The name is requested when the editor is opened",
"Doesnt belong to any group",
"Can review all the changes",
"Can perform all actions with comments",
"The file favorite state is undefined",
"Can't mention others in comments",
"Can't create new files from the editor"
];
@@users = [
User.new("uid-1", "John Smith", "smith@mail.ru", nil, nil, nil, [], @@descr_user_1),
User.new("uid-2", "Mark Pottato", "pottato@mail.ru", "group-2", ["group-2", ""], true, [], @@descr_user_2),
User.new("uid-3", "Hamish Mitchell", "mitchell@mail.ru", "group-3", ["group-2"], false, ["copy", "download", "print"], @@descr_user_3),
User.new("uid-0", nil, nil, nil, nil, nil, [], @@descr_user_0)
User.new("uid-1", "John Smith", "smith@mail.ru",
nil, nil, {},
nil, [], @@descr_user_1, true),
User.new("uid-2", "Mark Pottato", "pottato@mail.ru",
"group-2", ["group-2", ""], {
:view => "",
:edit => ["group-2", ""],
:remove => ["group-2"]
},
true, [], @@descr_user_2, false),
User.new("uid-3", "Hamish Mitchell", "mitchell@mail.ru",
"group-3", ["group-2"], {
:view => ["group-3", "group-2"],
:edit => ["group-2"],
:remove => []
},
false, ["copy", "download", "print"], @@descr_user_3, false),
User.new("uid-0", nil, nil,
nil, nil, {},
nil, [], @@descr_user_0, false)
]
class << self
@ -79,6 +106,17 @@ class Users
end
return @@users[0]
end
def get_users_for_mentions(id)
usersData = []
for user in @@users do
if (!user.id.eql?(id) && user.name != nil && user.email != nil)
usersData.push({:name => user.name, :email => user.email})
end
end
return usersData
end
end
end

View File

@ -129,16 +129,16 @@
};
<%
h = @file.get_history
if h %>
history = @file.get_history
if history %>
// the user is trying to show the document version history
config.events['onRequestHistory'] = function () {
docEditor.refreshHistory(<%= raw h[:hist].to_json %>); // show the document version history
docEditor.refreshHistory(<%= raw history[:hist].to_json %>); // show the document version history
};
// the user is trying to click the specific document version in the document version history
config.events['onRequestHistoryData'] = function (event) {
var ver = event.data;
var histData = <%= raw h[:histData].to_json %>;
var histData = <%= raw history[:histData].to_json %>;
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
};
// the user is trying to go back to the document from viewing the document version history
@ -148,6 +148,24 @@
<% end
%>
<%
usersMentions = @file.get_users_mentions
if usersMentions %>
// add mentions for not anonymous users
config.events['onRequestUsers'] = function () {
docEditor.setUsers({
"users": <%= raw @file.get_users_mentions.to_json %>
});
};
config.events['onRequestSendNotify'] = function (event) {
var actionLink = JSON.stringify(event.data.actionLink);
console.log("onRequestSendNotify:");
console.log(event.data);
console.log("Link to comment: " + replaceActionLink(location.href, actionLink));
};
<% end
%>
docEditor = new DocsAPI.DocEditor("iframeEditor", config);
};