刘光辉
7 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
package jnpf.bizcommon.onlyoffice.service.impl;
 
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeConfigParam;
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeProperties;
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeSessionEntity;
import jnpf.eln.RecordFillApi;
import jnpf.exception.DataException;
import org.junit.Test;
 
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
 
public class OnlyOfficeSceneConfigRegistryTest {
 
    @Test
    public void dispatchesKnownScenesOnceAndFallsBackToTheDefaultBuilder() {
        OnlyOfficeSceneConfigBuilder annotate = mock(OnlyOfficeSceneConfigBuilder.class);
        when(annotate.scene()).thenReturn("eln.template.annotate");
        when(annotate.bizModule()).thenReturn("eln.template");
        OnlyOfficeSceneConfigBuilder recordFill = mock(OnlyOfficeSceneConfigBuilder.class);
        when(recordFill.scene()).thenReturn("eln.record.fill");
        when(recordFill.bizModule()).thenReturn("eln.record");
        DefaultSceneConfigBuilder defaultBuilder = mock(DefaultSceneConfigBuilder.class);
        OnlyOfficeSceneConfigRegistry registry = new OnlyOfficeSceneConfigRegistry(
                Arrays.asList(annotate, recordFill), defaultBuilder);
 
        assertSame(recordFill, registry.resolve(param("eln.record.fill", "eln.record")));
        assertSame(annotate, registry.resolve(param("eln.template.annotate", "eln.template")));
        assertSame(defaultBuilder, registry.resolve(param("ordinary.view", "lims.document")));
 
        try {
            registry.resolve(param("eln.record.fill", "eln.template"));
            fail("scene and module mismatch must be rejected");
        } catch (DataException expected) {
            assertEquals("OnlyOffice 插件场景与业务模块不匹配", expected.getMessage());
        }
    }
 
    @Test
    public void recordFillBuilderOwnsAdmissionLockAndPluginContext() {
        RecordFillApi recordFillApi = mock(RecordFillApi.class);
        ActionResult<Boolean> allowed = mock(ActionResult.class);
        when(allowed.getCode()).thenReturn(200);
        when(allowed.getData()).thenReturn(true);
        when(recordFillApi.canFill(any(), any(), any(), any())).thenReturn(allowed);
        ElnRecordFillTicketIssuer ticketIssuer = mock(ElnRecordFillTicketIssuer.class);
        when(ticketIssuer.issue(any(), any(), any())).thenReturn("record-ticket");
        ElnRecordFillConfigBuilder builder = new ElnRecordFillConfigBuilder(recordFillApi, ticketIssuer);
        OnlyOfficeConfigParam param = param("eln.record.fill", "eln.record");
        param.setFileId("file-1");
        param.setFileType("annex");
        param.setBizDataId("record-1");
        UserInfo user = new UserInfo();
        user.setUserId("user-1");
        OnlyOfficeSessionEntity session = new OnlyOfficeSessionEntity();
        session.setTenantId("tenant-1");
        session.setFileId("file-1");
        session.setFileType("annex");
        session.setBizModule("eln.record");
        session.setBizDataId("record-1");
 
        OnlyOfficeSceneBuildPlan plan = builder.build(
                new OnlyOfficeSceneBuildContext(param, session, user, "tenant-1"));
        Map<String, Object> pluginContext = new LinkedHashMap<>();
        plan.customizePluginContext("eln-record-filler", "guid-1", pluginContext, true);
 
        assertTrue(plan.canEdit());
        assertTrue(plan.allowSameUserLockReopen());
        assertTrue(plan.hideCommentsWhenWritable());
        assertEquals(true, pluginContext.get("canFill"));
        assertEquals("onlyoffice:eln-record-fill", pluginContext.get("scope"));
        assertEquals("record-ticket", pluginContext.get("ticket"));
 
        Map<String, Object> unrelated = new LinkedHashMap<>();
        plan.customizePluginContext("document-helper", "guid-2", unrelated, true);
        assertFalse(unrelated.containsKey("ticket"));
    }
 
    @Test
    public void qianpiyeModeCanEditWithoutAPluginScene() {
        UserInfo administrator = mock(UserInfo.class);
        when(administrator.getIsAdministrator()).thenReturn(true);
        OnlyOfficeConfigParam param = new OnlyOfficeConfigParam();
        param.setMode("qianpiye");
 
        OnlyOfficeSceneBuildPlan plan = new DefaultSceneConfigBuilder(
                new OnlyOfficeEditPermissionEvaluator(new OnlyOfficeProperties())).build(
                new OnlyOfficeSceneBuildContext(param, new OnlyOfficeSessionEntity(), administrator, "tenant-1"));
 
        assertTrue(plan.canEdit());
    }
 
    @Test
    public void qianpiyeBuilderIssuesTicketOnlyForItsOwnWritablePlugin() {
        UserInfo administrator = mock(UserInfo.class);
        when(administrator.getIsAdministrator()).thenReturn(true);
        DmsQianpiyeTicketIssuer ticketIssuer = mock(DmsQianpiyeTicketIssuer.class);
        when(ticketIssuer.issue(any(), any(), any())).thenReturn("qianpiye-ticket");
        OnlyOfficeConfigParam param = param("dms.qianpiye", "dms");
        param.setFileId("file-1");
        DmsQianpiyeConfigBuilder builder = new DmsQianpiyeConfigBuilder(
                new OnlyOfficeEditPermissionEvaluator(new OnlyOfficeProperties()), ticketIssuer);
        OnlyOfficeSceneBuildPlan plan = builder.build(new OnlyOfficeSceneBuildContext(
                param, new OnlyOfficeSessionEntity(), administrator, "tenant-1"));
 
        Map<String, Object> context = new LinkedHashMap<>();
        plan.customizePluginContext("dms-qianpiye-annotator",
                "asc.{C764F7D6-055D-4C7D-97FD-83D2C4440585}", context, true);
 
        assertTrue(plan.canEdit());
        assertTrue(plan.allowSameUserLockReopen());
        assertTrue(plan.hideCommentsWhenWritable());
        assertEquals(true, context.get("canAnnotate"));
        assertEquals("onlyoffice:dms-qianpiye", context.get("scope"));
        assertEquals("qianpiye-ticket", context.get("ticket"));
        assertFalse(plan.keepPluginInReadOnly("dms-qianpiye-annotator", false));
    }
 
    @Test
    public void qianpiyeBuilderOnlyAdoptsAnIdleUnboundSessionForTheSameFile() {
        DmsQianpiyeConfigBuilder builder = new DmsQianpiyeConfigBuilder(
                new OnlyOfficeEditPermissionEvaluator(new OnlyOfficeProperties()), mock(DmsQianpiyeTicketIssuer.class));
        OnlyOfficeConfigParam param = param("dms.qianpiye", "dms");
        param.setFileId("file-1");
        param.setFileType("annex");
        param.setBizDataId("qianpiye-1");
        OnlyOfficeSessionEntity session = new OnlyOfficeSessionEntity();
        session.setTenantId("tenant-1");
        session.setFileId("file-1");
        session.setFileType("annex");
        session.setSessionStatus(OnlyOfficeSessionEntity.SessionStatus.IDLE);
 
        assertTrue(builder.canAdoptUnboundSession(session, param, "tenant-1"));
 
        // 旧版普通编辑会话可能记录了页面模块,但尚未绑定具体业务记录,允许签批页迁移。
        session.setBizModule("签批页管理");
        assertTrue(builder.canAdoptUnboundSession(session, param, "tenant-1"));
 
        session.setBizDataId("another-business");
        assertFalse(builder.canAdoptUnboundSession(session, param, "tenant-1"));
        session.setBizDataId(null);
        session.setSessionStatus(OnlyOfficeSessionEntity.SessionStatus.EDITING);
        assertFalse(builder.canAdoptUnboundSession(session, param, "tenant-1"));
    }
 
    @Test
    public void qianpiyeSessionCanBeReusedWithoutBizDataId() {
        DmsQianpiyeConfigBuilder builder = new DmsQianpiyeConfigBuilder(
                new OnlyOfficeEditPermissionEvaluator(new OnlyOfficeProperties()), mock(DmsQianpiyeTicketIssuer.class));
        OnlyOfficeSessionEntity session = new OnlyOfficeSessionEntity();
        session.setTenantId("tenant-1");
        session.setFileId("file-1");
        session.setFileType("annex");
        session.setBizModule("dms");
        session.setBizDataId("qianpiye-1");
 
        OnlyOfficeConfigParam genericPreview = new OnlyOfficeConfigParam();
        genericPreview.setFileId("file-1");
        genericPreview.setFileType("annex");
        genericPreview.setMode("view");
        assertTrue(builder.matchesSession(session, genericPreview, "tenant-1"));
 
        OnlyOfficeConfigParam annotation = param("dms.qianpiye", "dms");
        annotation.setFileId("file-1");
        annotation.setFileType("annex");
        annotation.setMode("qianpiye");
        assertTrue(builder.matchesSession(session, annotation, "tenant-1"));
 
        OnlyOfficeConfigParam otherBusiness = param("eln.record.fill", "eln.record");
        otherBusiness.setFileId("file-1");
        otherBusiness.setFileType("annex");
        otherBusiness.setMode("view");
        assertFalse(builder.matchesSession(session, otherBusiness, "tenant-1"));
 
        annotation.setBizDataId("another-business");
        assertFalse(builder.matchesSession(session, annotation, "tenant-1"));
    }
 
    @Test(expected = IllegalStateException.class)
    public void rejectsDuplicateSceneBuilders() {
        OnlyOfficeSceneConfigBuilder first = builder("eln.record.fill", "eln.record");
        OnlyOfficeSceneConfigBuilder duplicate = builder("eln.record.fill", "eln.other-record");
 
        new OnlyOfficeSceneConfigRegistry(Arrays.asList(first, duplicate),
                mock(DefaultSceneConfigBuilder.class));
    }
 
    @Test(expected = IllegalStateException.class)
    public void rejectsDuplicateBusinessModuleGuards() {
        OnlyOfficeSceneConfigBuilder first = builder("eln.record.fill", "eln.record");
        OnlyOfficeSceneConfigBuilder duplicate = builder("eln.record.review", "eln.record");
 
        new OnlyOfficeSceneConfigRegistry(Arrays.asList(first, duplicate),
                mock(DefaultSceneConfigBuilder.class));
    }
 
    private OnlyOfficeSceneConfigBuilder builder(String scene, String module) {
        OnlyOfficeSceneConfigBuilder builder = mock(OnlyOfficeSceneConfigBuilder.class);
        when(builder.scene()).thenReturn(scene);
        when(builder.bizModule()).thenReturn(module);
        when(builder.guardsBusinessContext()).thenReturn(true);
        return builder;
    }
 
    private OnlyOfficeConfigParam param(String scene, String module) {
        OnlyOfficeConfigParam param = new OnlyOfficeConfigParam();
        param.setBizScene(scene);
        param.setBizModule(module);
        return param;
    }
}