v0.0.3
authorVásáry Dániel <vasary@elgekko.net>
Wed, 10 Jan 2024 15:40:36 +0000 (16:40 +0100)
committerVásáry Dániel <vasary@elgekko.net>
Wed, 10 Jan 2024 15:40:36 +0000 (16:40 +0100)
66 files changed:
mc-vod-sync/QUESTIONS.md
mc-vod-sync/mc-vod-sync-app/pom.xml
mc-vod-sync/mc-vod-sync-app/src/main/resources/application-dev.yaml
mc-vod-sync/mc-vod-sync-app/src/main/resources/application.yaml
mc-vod-sync/mc-vod-sync-app/src/main/resources/logback-prod.xml [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-app/src/main/resources/logback-spring.xml
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetExportIT.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetImportExportBase.java
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetImportIT.java [moved from mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetImportExportIT.java with 55% similarity]
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetMapperIT.java
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/BrightCoveClientIT.java
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/EmailSendServiceIT.java [moved from mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/EmailSendServiceTest.java with 53% similarity]
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/ExecutionLockIT.java
mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/RepositoryIT.java
mc-vod-sync/mc-vod-sync-app/src/test/resources/testdata-duplicate-video.xlsx [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-brightcove/src/main/java/hu/user/mcvodsync/brightcove/ApiProperties.java
mc-vod-sync/mc-vod-sync-brightcove/src/main/java/hu/user/mcvodsync/brightcove/BrightCoveClient.java
mc-vod-sync/mc-vod-sync-db/migrations/bootstrap.sql
mc-vod-sync/mc-vod-sync-db/migrations/scripts/003_create_business_tables.sql
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/Asset.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/AssetSync.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/Associate.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/PlaylistSync.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/UploadFile.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/converter/StringListConverter.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/repository/AssetRepository.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/repository/AssetSyncRepository.java
mc-vod-sync/mc-vod-sync-db/src/main/java/hu/user/mcvodsync/db/repository/PlaylistSyncRepository.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/ServiceProperties.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/config/ScheduledTasks.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/CompositeSummary.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/Summary.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportCompletedEvent.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportStartedEvent.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportCompletedEvent.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/AssetImportService.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/AssetMapper.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/ImportSummary.java [deleted file]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/VodXlsProcessor.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/mail/EmailSendService.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/SyncExportService.java [moved from mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/AssetExportService.java with 62% similarity]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/SyncProcessor.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/VideoMapper.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledExport.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledImport.java
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledSunsetChacker.java [moved from mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledSunriseChacker.java with 91% similarity]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/time/TimeUtils.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/ApplicationProperties.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/Constants.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/config/ResourceConfigurer.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/config/WebSecurityConfig.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCovePlaylistDataModel.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCoveVideoDataModel.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ExportDataViewModel.java [deleted file]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportEventHandler.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/IndexViewModel.java
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/MainViewModel.java [moved from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportFileViewModel.java with 91% similarity]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/metainfo/zk/zk.xml
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/associates.zul
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/browse-remote.zul
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/export-stats.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/import-stats.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/test.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/import-file.zul [deleted file]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/index.zul
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/main.zul [new file with mode: 0644]

index d1c780a2849ecc9719c5fc577487755346d82479..c8db0b0f52fa29aca2e6095cfc823bf8cdd023fe 100644 (file)
@@ -1,3 +1,6 @@
+- Az extra notes hogyan értelmezendő?
+- Egy video lehet e többször hozzáadva gyan ahhoz a listához? Ha nem ,kéne csekkolni betöltésnél...
+
 actors_talent, Actors/Talent, , string, null required: false
 director, Director, , string, null required: false
 episode, Episode, ,
index 7bf9f2ceb0ae15b6e09afa494944489f8f9d94f6..b73d56eb9e44d4d7115e9093bb511cda5ace035b 100644 (file)
@@ -3,7 +3,7 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <artifactId>mc-vod-sync-app</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
+    <version>0.0.3</version>
     <parent>
         <groupId>hu.user</groupId>
         <artifactId>mc-vod-sync</artifactId>
index e5fc5a9c40b060b77ee94f2427d7cc6bd9c4bd21..f2b12d1b461977e18b90d83ccfe715e4daaff68c 100644 (file)
@@ -25,13 +25,14 @@ spring:
     username: db2admin
     password: password
   mail:
-    host: mx.in.useribm.hu
+#    host: mx.in.useribm.hu
 #    port: 587
 #  spring.mail.username=<login user to smtp server>
 #  spring.mail.password=<login password to smtp server>
 #  spring.mail.properties.mail.smtp.auth=true
 #  spring.mail.properties.mail.smtp.starttls.enable=true
 logging:
+  config:
   level:
     org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR
 #    org.springframework.web.client.RestTemplate: DEBUG
@@ -39,19 +40,24 @@ logging:
 #    httpclient.wire: DEBUG
 mc-vod-sync:
   service:
-    target-video-insert-enabled: true
-    target-playlist-insert-enabled: true
+    target-video-insert-enabled: false
+    target-playlist-insert-enabled: false
     scheduler:
       import-enabled: false
       export-enabled: false
-      sunrise-checker-enabled: false
+      sunset-checker-enabled: false
       import-cron: 0 0 4 1/1 * ? *
       export-cron: 0 0 4 1/1 * ? *
-      sunrise-checker-cron: 0 0 4 1/1 * ? *
+      sunset-checker-cron: 0 0 4 1/1 * ? *
+    report:
+      recipient: vasary@elgekko.net
+      sender: noreply@mc-vod-sync
   application:
     user-name: user
     password: password
+    admin: true
   api:
+    base-url: https://cms.api.brightcove.com
     token-request-url: https://oauth.brightcove.com/v4/access_token
     client-id: 0337034f-bde3-44d4-81ba-6a4566ca8ba0
     client-secret: 03Az2W6BSj4sTPSU7SVnRcJ6NDmeaFmB7EPbmuZFnt5slaC2bbscBOMvKR03CGVMxaVXUo9ao6e_gLvxUCjtgg
index 39be721846975adc33847ae0bf4310050597d4a9..00b7dec1aaff4c376907f5d189756c5f54b7d1c4 100644 (file)
@@ -1,5 +1,5 @@
 server:
-  port: 8080
+  port: 80
   servlet:
     context-path: /
 zk:
@@ -7,9 +7,7 @@ zk:
   zul-view-resolver-enabled: true
 spring:
   jpa:
-    #    hibernate:
-    #      use-new-id-generator-mappings: true
-    show-sql: true
+    show-sql: false
     properties:
       hibernate:
         format_sql: true
@@ -20,37 +18,40 @@ spring:
       enabled: always
   datasource:
     type: com.zaxxer.hikari.HikariDataSource
-    url: jdbc:db2://dvdev.in.useribm.hu:50000/vodsync
+    url: jdbc:db2://localhost:25000/vodsync
+    retrieveMessagesFromServerOnGetMessage: true
     username: db2admin
-    password: password
-camunda.bpm:
-  generic-properties.properties:
-    telemetry-reporter-activate: false
-  job-executor-acquire-by-priority: true
-  job-execution:
-    core-pool-size: 10
-    #lock-time-in-millis: 600000
-  database:
-    type: db2
-    schema-update: false
-    table-prefix: CAMUNDA.
-    schema-name: CAMUNDA
-  webapp:
-    enabled: true
-    index-redirect-enabled: false
-  admin-user:
-    id: kermit
-    password: password
-    firstName: Kermit
-  filter:
-    create: All tasks
-  job-execution.enabled: true
+    password: Password01
+  mail:
+    host: mx.in.useribm.hu
+#   port: 587
+#   username=<login user to smtp server>
+#   password=<login password to smtp server>
+#   properties.mail.smtp.auth=true
+#   properties.mail.smtp.starttls.enable=true
 logging:
-  #  config: classpath:log4j2.xml
-  level:
-    org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR
-#    org.springframework.security: DEBUG
-#    org.springframework.security.web: INFO
-#  pattern:
-#    console: "%d %-5level %logger : %msg%n"
-#    file: "%d %-5level [%thread] %logger : %msg%n"
\ No newline at end of file
+  config: logback-prod.xml
+mc-vod-sync:
+  service:
+    target-video-insert-enabled: false
+    target-playlist-insert-enabled: false
+    scheduler:
+      import-enabled: false
+      export-enabled: false
+      sunset-checker-enabled: false
+      import-cron: 0 0 4 1/1 * ? *
+      export-cron: 0 0 4 1/1 * ? *
+      sunset-checker-cron: 0 0 4 1/1 * ? *
+    report:
+      recipient: vasary@elgekko.net
+      sender: noreply@mc-vod-sync
+  application:
+    user-name: user
+    password: password
+    admin: true
+  api:
+    base-url: https://cms.api.brightcove.com
+    token-request-url: https://oauth.brightcove.com/v4/access_token
+    client-id: 0337034f-bde3-44d4-81ba-6a4566ca8ba0
+    client-secret: 03Az2W6BSj4sTPSU7SVnRcJ6NDmeaFmB7EPbmuZFnt5slaC2bbscBOMvKR03CGVMxaVXUo9ao6e_gLvxUCjtgg
+    account-id: 6302605131001
diff --git a/mc-vod-sync/mc-vod-sync-app/src/main/resources/logback-prod.xml b/mc-vod-sync/mc-vod-sync-app/src/main/resources/logback-prod.xml
new file mode 100644 (file)
index 0000000..049a51f
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="LOGNAME" value="mc-vod-sync"/>
+    <property name="LOGS" value="./logs"/>
+
+    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <Pattern>
+                %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
+            </Pattern>
+        </layout>
+    </appender>
+
+    <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOGS}/${LOGNAME}.log</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOGS}/archived/${LOGNAME}-%d{yyyy-MM-dd}.log.zip</fileNamePattern>
+        </rollingPolicy>
+    </appender>
+
+    <springProfile name="prod">
+        <root level="INFO">
+            <appender-ref ref="Console"/>
+        </root>
+        <root level="INFO">
+            <appender-ref ref="RollingFile"/>
+        </root>
+    </springProfile>
+
+</configuration>
\ No newline at end of file
index 153ccc4f31cc9350ecc05b7a1c7e7b7ddfc98a3e..d20bc1c5c6b3f794df86b4b2e9acde5961a4bfb3 100644 (file)
@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
-    <include resource="org/springframework/boot/logging/logback/base.xml"/>
+    <!--    <include resource="org/springframework/boot/logging/logback/base.xml"/>-->
     <!--    <property name="LOGS" value="./logs"/>-->
 
     <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
         <layout class="ch.qos.logback.classic.PatternLayout">
             <Pattern>
-                %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
+                %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): [%F:%L] %msg%n %throwable
             </Pattern>
         </layout>
     </appender>
     <!--    </appender>-->
 
     <springProfile name="dev">
-        <logger name="org.springframework" level="INFO" additivity="false">
-            <appender-ref ref="CONSOLE"/>
-        </logger>
+        <!--        <logger name="hu.user.mcvodsync" level="INFO" additivity="false">-->
+        <!--            <appender-ref ref="Console"/>-->
+        <!--        </logger>-->
+        <!--        <logger name="org.springframework" level="INFO" additivity="false">-->
+        <!--            <appender-ref ref="Console"/>-->
+        <!--        </logger>-->
         <root level="INFO">
-            <appender-ref ref="CONSOLE"/>
+            <appender-ref ref="Console"/>
         </root>
     </springProfile>
 
diff --git a/mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetExportIT.java b/mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetExportIT.java
new file mode 100644 (file)
index 0000000..b89cec8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) $today.year-$today.month-24.
+ * By elGekko
+ */
+
+package hu.user.mcvodsync;
+
+import lombok.extern.log4j.Log4j2;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+
+@Log4j2
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@ActiveProfiles("dev")
+@TestPropertySource("classpath:application-dev.yaml")
+public class AssetExportIT extends AssetImportExportBase {
+
+    @Test
+    public void initialLoadTest() throws Exception {
+        cleanupLocal();
+        importFile("src/test/resources/testdata.xlsx");
+        cleanupRemote();
+        exportData();
+        assertSynchronized();
+    }
+
+    @Test
+    public void changeVideoTest() throws Exception {
+        cleanupLocal();
+        importFile("src/test/resources/testdata.xlsx");
+        importFile("src/test/resources/testdata-change-video.xlsx");
+        cleanupRemote();
+        exportData();
+        assertSynchronized();
+    }
+
+    @Test
+    public void deleteVideoTest() throws Exception {
+        cleanupLocal();
+        importFile("src/test/resources/testdata.xlsx");
+        importFile("src/test/resources/testdata-delete-video.xlsx");
+        cleanupRemote();
+        exportData();
+        assertSynchronized();
+    }
+
+    @Test
+    public void changePlaylistOrderTest() throws Exception {
+        cleanupLocal();
+        importFile("src/test/resources/testdata.xlsx");
+        importFile("src/test/resources/testdata-change-playlist-order.xlsx");
+        cleanupRemote();
+        exportData();
+        assertSynchronized();
+    }
+
+    @Test
+    public void duplicateVideoTest() throws Exception {
+        cleanupLocal();
+        importFile("src/test/resources/testdata.xlsx");
+        importFile("src/test/resources/testdata-duplicate-video.xlsx");
+        cleanupRemote();
+        exportData();
+        assertSynchronized();
+    }
+
+
+}
index 050b363e33cc1a668d1680c1c3b2fcee1b675fc0..43e937358f89e0439e5260f907a62828e0d8dad4 100644 (file)
@@ -15,10 +15,11 @@ import hu.user.mcvodsync.db.SyncType;
 import hu.user.mcvodsync.db.repository.AssetRepository;
 import hu.user.mcvodsync.db.repository.AssetSyncRepository;
 import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
+import hu.user.mcvodsync.service.data.CompositeSummary;
+import hu.user.mcvodsync.service.data.Summary;
 import hu.user.mcvodsync.service.in.AssetImportService;
-import hu.user.mcvodsync.service.in.ImportSummary;
 import hu.user.mcvodsync.service.in.VodXlsProcessor;
-import hu.user.mcvodsync.service.out.AssetExportService;
+import hu.user.mcvodsync.service.out.SyncProcessor;
 import hu.user.mcvodsync.service.out.VideoMapper;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
@@ -55,7 +56,7 @@ public class AssetImportExportBase {
     private AssetImportService assetImportService;
 
     @Autowired
-    private AssetExportService assetExportService;
+    private SyncProcessor syncProcessor;
 
     @Autowired
     private BrightCoveClient brightCoveClient;
@@ -66,22 +67,41 @@ public class AssetImportExportBase {
     protected String getPlaylistSyncIds(String name) {
         List<PlaylistSync> playlists = playlistSyncRepository.findAllByName(name);
         assertEquals(1, playlists.size());
-        return StringUtils.join(playlists.get(0).getIds(), ",");
+        List<String> catalogIds = playlists.get(0).getIds().stream().map(assetRepository::findCatalogIdById).collect(Collectors.toList());
+        return StringUtils.join(catalogIds, ",");
     }
 
-    protected void cleanup() {
+    protected void cleanup() throws Exception {
         cleanupLocal();
         cleanupRemote();
         assetRepository.deleteAllInBatch();
     }
 
-    protected void cleanupRemote() {
+    protected void cleanupRemote() throws InterruptedException {
         log.info("cleanupRemote");
         cleanupRemotePlaylists();
+        waitForPlaylistCleanupCompleted();
+        Thread.sleep(3000);
         cleanupRemoteVideos();
+        waitForVideoCleanupCompleted();
         log.info("cleanupRemote OK");
     }
 
+    private void waitForVideoCleanupCompleted() {
+        while (true) {
+            int count = 0;
+            PagedSearch<Video> page = PagedSearch.<Video>builder()
+                    .query("tags:mc-vod-sync")
+                    .build();
+            while (brightCoveClient.getVideosPaged(page)) {
+                count += page.getData().size();
+            }
+            if (count == 0) {
+                break;
+            }
+        }
+    }
+
     private void cleanupRemoteVideos() {
         PagedSearch<Video> page = PagedSearch.<Video>builder()
                 .query("tags:mc-vod-sync")
@@ -101,6 +121,22 @@ public class AssetImportExportBase {
         }
     }
 
+    private void waitForPlaylistCleanupCompleted() {
+        while (true) {
+            int count = 0;
+            PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                    .query("description:mc-vod-sync")
+                    .sort("name")
+                    .build();
+            while (brightCoveClient.getPlaylistsPaged(page)) {
+                count += page.getData().size();
+            }
+            if (count == 0) {
+                break;
+            }
+        }
+    }
+
     private void cleanupRemotePlaylists() {
         PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
                 .query("description:mc-vod-sync")
@@ -121,13 +157,20 @@ public class AssetImportExportBase {
 
     protected void cleanupLocal() {
         log.info("cleanupLocal");
+        assetRepository.deleteAllInBatch();
+        cleanupLocalSync();
+        log.info("cleanupLocal OK");
+    }
+
+    protected void cleanupLocalSync() {
+        log.info("cleanupLocalSync");
         playlistSyncRepository.deleteAllInBatch();
         assetSyncRepository.deleteAllInBatch();
-        log.info("cleanupLocal OK");
+        log.info("cleanupLocalSync OK");
     }
 
-    protected ImportSummary importFile(String xlsFile) {
-        ImportSummary summary;
+    protected CompositeSummary importFile(String xlsFile) {
+        CompositeSummary summary;
         try {
             Path input = Paths.get(xlsFile);
             summary = vodXlsProcessor.process(input.getFileName().toString(), Files.readAllBytes(input));
@@ -139,14 +182,14 @@ public class AssetImportExportBase {
     }
 
     protected void exportData() {
-        assetExportService.export();
+        syncProcessor.export();
     }
 
 
     protected void assertSynchronized() {
         List<Asset> assets = assetRepository.findAll();
         assets.forEach(this::assertVideoSynchronized);
-        Map<String, List<String>> playLists = assetImportService.getPlayLists();
+        Map<String, List<Long>> playLists = assetImportService.getPlayLists();
         playLists.forEach(this::assertPlaylistSynchronized);
     }
 
@@ -165,7 +208,7 @@ public class AssetImportExportBase {
         assertEquals(asset.getProductionYear(), remoteAsset.getProductionYear());
     }
 
-    protected void assertPlaylistSynchronized(String playlistName, List<String> ids) {
+    protected void assertPlaylistSynchronized(String playlistName, List<Long> ids) {
         Playlist playlist = null;
         try {
             playlist = brightCoveClient.getPlaylistsByName(playlistName);
@@ -173,16 +216,18 @@ public class AssetImportExportBase {
         }
         assertNotNull(playlist);
         assertNotNull(playlist.getVideoIds());
-        List<String> remoteIds = playlist.getVideoIds().stream().map(assetRepository::findCatalogIdByReferenceId).collect(Collectors.toList());
-        assertEquals(ids, remoteIds);
+        List<String> remoteIds = playlist.getVideoIds().stream().map(id -> assetRepository.findIdByReferenceId(id, playlistName)).collect(Collectors.toList());
+        String actual = StringUtils.join(remoteIds, ",");
+        String expected = StringUtils.join(ids.stream().map(String::valueOf).collect(Collectors.toList()), ",");
+        assertEquals(expected, actual);
     }
 
-    protected void checkSummary(ImportSummary summary, long expectedAll, long expectedInsert, long expectedUpdate, long expectedDelete) {
+    protected void checkSummary(Summary summary, long expectedAll, long expectedInsert, long expectedUpdate, long expectedDelete) {
         assertEquals(expectedAll, summary.getAll());
         assertEquals(expectedAll, summary.getSuccess());
-        assertEquals(expectedInsert, summary.getInserted());
-        assertEquals(expectedUpdate, summary.getUpdated());
-        assertEquals(expectedDelete, summary.getDeleted());
+        assertEquals(expectedInsert, summary.getInsert());
+        assertEquals(expectedUpdate, summary.getUpdate());
+        assertEquals(expectedDelete, summary.getDelete());
     }
 
     protected void checkAsset(long expected, SyncType syncType, long expectedAllCount) {
similarity index 55%
rename from mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetImportExportIT.java
rename to mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/AssetImportIT.java
index cda0ee674e9f1212b3b63ab41e712374bb4febef..a7a5911cdaab1161a60ab3e932805689536b3bc8 100644 (file)
@@ -6,7 +6,7 @@
 package hu.user.mcvodsync;
 
 import hu.user.mcvodsync.db.SyncType;
-import hu.user.mcvodsync.service.in.ImportSummary;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import lombok.extern.log4j.Log4j2;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -28,7 +28,7 @@ import static org.junit.Assert.assertEquals;
 @SpringBootTest
 @ActiveProfiles("dev")
 @TestPropertySource("classpath:application-dev.yaml")
-public class AssetImportExportIT extends AssetImportExportBase {
+public class AssetImportIT extends AssetImportExportBase {
 
     @BeforeClass
     public static void beforeClass() {
@@ -42,30 +42,41 @@ public class AssetImportExportIT extends AssetImportExportBase {
     public void init() {
     }
 
+    //    @Test
+    public void initialBigLoadTest() throws IOException {
+        log.info("initialBigLoadTest");
+        cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata-big.xlsx");
+//        checkSummary(summary.getVideo(), 9, 9, 0, 0);
+//        checkAsset(9, SyncType.INSERT, 9);
+//        checkPlaylist(3, SyncType.INSERT, 3);
+//        assertEquals("CCEM110180,CCEM110183,CCEM110068", getPlaylistSyncIds("Playlist1"));
+//        assertEquals("CCEM128963,CCEM128965,CCEM128967", getPlaylistSyncIds("Playlist2"));
+//        assertEquals("CCEF008678,CCEM001148,CCEM072086", getPlaylistSyncIds("Playlist3"));
+    }
+
     @Test
     public void initialLoadTest() throws IOException {
 //        Path xlsFile = Paths.get("src/test/resources/testdata-big.xlsx");
         log.info("initialLoadTest");
-        cleanup();
-        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
-        checkSummary(summary, 9, 9, 0, 0);
+        cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata.xlsx");
+        checkSummary(summary.getVideo(), 9, 9, 0, 0);
         checkAsset(9, SyncType.INSERT, 9);
         checkPlaylist(3, SyncType.INSERT, 3);
         assertEquals("CCEM110180,CCEM110183,CCEM110068", getPlaylistSyncIds("Playlist1"));
         assertEquals("CCEM128963,CCEM128965,CCEM128967", getPlaylistSyncIds("Playlist2"));
         assertEquals("CCEF008678,CCEM001148,CCEM072086", getPlaylistSyncIds("Playlist3"));
-
-        exportData();
-        assertSynchronized();
     }
 
     @Test
     public void changeVideoTest() throws IOException {
         log.info("changeVideoTest");
-        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
         cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocalSync();
         summary = importFile("src/test/resources/testdata-change-video.xlsx");
-        checkSummary(summary, 9, 0, 1, 0);
+        checkSummary(summary.getVideo(), 9, 0, 1, 0);
         checkAsset(1, SyncType.UPDATE, 1);
         checkPlaylist(0, null, 0);
     }
@@ -73,12 +84,12 @@ public class AssetImportExportIT extends AssetImportExportBase {
     @Test
     public void deleteVideoTest() {
         log.info("deleteVideoTest");
-        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
         cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocalSync();
         summary = importFile("src/test/resources/testdata-delete-video.xlsx");
-        checkSummary(summary, 9, 0, 1, 1);
-        checkAsset(1, SyncType.UPDATE, 2);
-        checkAsset(1, SyncType.DELETE, 2);
+        checkSummary(summary.getVideo(), 9, 0, 0, 1);
+        checkAsset(1, SyncType.DELETE, 1);
         checkPlaylist(1, SyncType.UPDATE, 1);
         assertEquals("CCEM110180,CCEM110183", getPlaylistSyncIds("Playlist1"));
     }
@@ -86,14 +97,28 @@ public class AssetImportExportIT extends AssetImportExportBase {
     @Test
     public void changePlaylistOrderTest() {
         log.info("changePlaylistOrderTest");
-        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
         cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocalSync();
         summary = importFile("src/test/resources/testdata-change-playlist-order.xlsx");
-        checkSummary(summary, 8, 0, 1, 0);
+        checkSummary(summary.getVideo(), 8, 0, 1, 0);
         checkAsset(1, SyncType.UPDATE, 1);
         checkPlaylist(1, SyncType.UPDATE, 1);
         assertEquals("CCEM001148,CCEM072086,CCEF008678", getPlaylistSyncIds("Playlist3"));
     }
 
 
+    @Test
+    public void duplicateVideoTest() throws IOException {
+        log.info("changeVideoTest");
+        cleanupLocal();
+        CompositeSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocalSync();
+        summary = importFile("src/test/resources/testdata-duplicate-video.xlsx");
+        checkSummary(summary.getVideo(), 10, 1, 0, 0);
+        checkAsset(1, SyncType.INSERT, 1);
+        checkPlaylist(1, SyncType.INSERT, 1);
+        assertEquals("CCEF008678", getPlaylistSyncIds("Playlist4"));
+    }
+
 }
index b11b2f71cd401c4dffba99515250ec66089e2c65..3205f06fcedc695204c7ba7f1e200c1b03cde6cb 100644 (file)
@@ -40,7 +40,7 @@ public class AssetMapperIT {
 
         assertEquals(asset.getCatalogId(), video.getReferenceId());
         assertEquals(asset.getProgLocalTitle(), video.getName());
-        assertEquals(asset.getHubInfo(), video.getCustomFields().get(VideoMapper.NOTES));
+        assertEquals(asset.getHubInfo(), video.getCustomFields().get(VideoMapper.CUSTOM_NOTES));
     }
 
     @Test
@@ -48,11 +48,12 @@ public class AssetMapperIT {
         Video video = new Video();
         video.setReferenceId("setReferenceId");
         video.setName("name");
-        video.putCustomFieldsItem(VideoMapper.NOTES, "notes");
+        video.putCustomFieldsItem(VideoMapper.CUSTOM_NOTES, "notes");
         Asset asset = videoMapper.toAsset(video);
 
         assertEquals(video.getReferenceId(), asset.getCatalogId());
         assertEquals(video.getName(), asset.getProgLocalTitle());
-        assertEquals(video.getCustomFields().get(VideoMapper.NOTES), asset.getHubInfo());
+        assertEquals(video.getCustomFields().get(VideoMapper.CUSTOM_NOTES), asset.getHubInfo());
     }
+
 }
index 1f20e9b13643894ba275aafcbe6ac2a9876d20e2..7f8b96684922185067a3f31f1da1ce2b470b4194 100644 (file)
@@ -36,6 +36,12 @@ public class BrightCoveClientIT {
     @Autowired
     private BrightCoveClient bcClient;
 
+    @Test
+    public void testGetPlaylistById() {
+        Playlist playList = bcClient.getPlaylistsById("1760978144285528866");
+        logPlaylist(playList);
+    }
+
 
     private List<String> getVideos() {
         List<String> ids = new ArrayList<>();
@@ -125,7 +131,7 @@ public class BrightCoveClientIT {
     @Test
     public void testGetPlayListsByName() {
         PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
-                .query("name:Playlist 0000")
+                .query("name:Playlist1")
                 .sort("name")
                 .build();
 
@@ -165,7 +171,8 @@ public class BrightCoveClientIT {
         Video video = new Video();
         video.setName("TEST video 00001");
         video.setReferenceId("MCVODSYNC10001");
-        video.setTags(Collections.singletonList("mc-vod-sync"));
+        video.addTagsItem("tag1");
+        video.addTagsItem("mc-vod-sync");
         video.setCustomFields(ImmutableMap.of("Notes", "notes"));
         Video createdVideo = bcClient.createVideo(video);
         logVideo(createdVideo);
@@ -201,6 +208,33 @@ public class BrightCoveClientIT {
         logVideo(createdVideo);
     }
 
+    @Test
+    public void testCreateAndUpdateVideo() {
+        String refId = "MCVODSYNC00012";
+        Video video = bcClient.getVideoByReferenceId(refId);
+        if (Objects.isNull(video)) {
+            video.setName("TEST video 0000 for update");
+            video.setReferenceId(refId);
+            video.setTags(Collections.singletonList("mc-vod-sync"));
+            video = bcClient.createVideo(video);
+        }
+        video.setName("TEST video 0000 for update " + System.currentTimeMillis());
+        video = bcClient.updateVideo(video.getId(), video);
+        logVideo(video);
+    }
+
+    @Test
+    public void testCheckVideos() {
+        Video video = bcClient.getVideoByReferenceId("CCEM110068");
+        logVideo(video);
+        video = bcClient.getVideoByReferenceId("CCEM110180");
+        logVideo(video);
+        video = bcClient.getVideoByReferenceId("CCEM110183");
+        logVideo(video);
+        video = bcClient.getVideoByReferenceId("CCEM110185");
+        logVideo(video);
+    }
+
     @Test
     public void testGetCustomFields() {
         VideoFields videoFields = bcClient.getVideoCustomFields();
similarity index 53%
rename from mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/EmailSendServiceTest.java
rename to mc-vod-sync/mc-vod-sync-app/src/test/java/hu/user/mcvodsync/EmailSendServiceIT.java
index 5976c9117197e6a28d88f9947209a438c00ad1f4..8805d10567e9c1bba8b8ce08d3142910149b7fac 100644 (file)
@@ -5,21 +5,29 @@
 
 package hu.user.mcvodsync;
 
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import hu.user.mcvodsync.service.mail.EmailSendService;
-import org.junit.jupiter.api.Test;
+import lombok.extern.log4j.Log4j2;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.time.Duration;
+import java.time.Instant;
 
+
+@Log4j2
 @RunWith(SpringRunner.class)
+@ComponentScan("hu.user.mcvodsync")
 @SpringBootTest
 @ActiveProfiles("dev")
 @TestPropertySource("classpath:application-dev.yaml")
-public class EmailSendServiceTest {
+public class EmailSendServiceIT {
 
     @Autowired
     EmailSendService emailSendService;
@@ -27,7 +35,12 @@ public class EmailSendServiceTest {
 
     @Test
     public void sendEmail() {
-        emailSendService.sendSimpleMessage();
+        CompositeSummary summary = CompositeSummary.builder().build();
+        summary.setStarted(Instant.now());
+        summary.setFinished(Instant.now().plus(Duration.ofHours(1)));
+        emailSendService.sendSimpleMessage("BrightCove export report", summary);
+        log.info("Test email sent");
     }
 
+
 }
index 26f991a94ddb70fbb5f7e0fe1d8363ec1839ec40..9e8f09745d1c62ff7e6dac944c81a22e994aa53e 100644 (file)
@@ -5,7 +5,7 @@
 
 package hu.user.mcvodsync;
 
-import hu.user.mcvodsync.service.schedule.ScheduledSunriseChacker;
+import hu.user.mcvodsync.service.schedule.ScheduledSunsetChacker;
 import lombok.extern.log4j.Log4j2;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,14 +30,14 @@ public class ExecutionLockIT {
     private TaskScheduler taskScheduler;
 
     @Autowired
-    private ScheduledSunriseChacker scheduledSunriseChacker;
+    private ScheduledSunsetChacker scheduledSunsetChacker;
 
     @Test
     public void testSemaphore() throws InterruptedException {
         log.info("Test start");
         Thread.sleep(1000);
 
-        taskScheduler.schedule(scheduledSunriseChacker, Instant.now());
+        taskScheduler.schedule(scheduledSunsetChacker, Instant.now());
         Thread.sleep(5000);
         log.info("Test finish");
     }
index fce3b775b1a41c5a2730fc122f3abf53675549ff..8a6940405e3480eba639f7245162f76dea38d46f 100644 (file)
@@ -6,14 +6,15 @@
 package hu.user.mcvodsync;
 
 import com.google.common.collect.Lists;
+import hu.user.mcvodsync.db.Asset;
 import hu.user.mcvodsync.db.AssetSync;
 import hu.user.mcvodsync.db.PlaylistSync;
 import hu.user.mcvodsync.db.SyncType;
 import hu.user.mcvodsync.db.repository.AssetRepository;
 import hu.user.mcvodsync.db.repository.AssetSyncRepository;
 import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import hu.user.mcvodsync.service.in.AssetImportService;
-import hu.user.mcvodsync.service.in.ImportSummary;
 import lombok.extern.log4j.Log4j2;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,19 +58,19 @@ public class RepositoryIT {
         List<String> playlists = assetRepository.queryDistinctPlaylists();
         assertNotNull(playlists);
 
-        List<String> assets = assetRepository.queryPlaylistsAssets(playlists.get(0));
+        List<Long> assets = assetRepository.queryPlaylistsAssets(playlists.get(0));
         assertNotNull(assets);
     }
 
     @Test
     public void queryExpired() {
         LocalDate currentDate = LocalDate.parse("2000-01-02", DateTimeFormatter.ISO_LOCAL_DATE);
-        List<String> ids = assetRepository.queryExpired(Date.valueOf(currentDate));
+        List<Asset> ids = assetRepository.queryExpired(Date.valueOf(currentDate));
         assertNotNull(ids);
         assertEquals(1, ids.size());
 
-        ImportSummary summary = ImportSummary.builder().build();
-        assetImportService.removeExpired(currentDate);
+        CompositeSummary summary = CompositeSummary.builder().build();
+        assetImportService.removeExpired(currentDate, summary);
 
         ids = assetRepository.queryExpired(Date.valueOf(currentDate));
         assertNotNull(ids);
@@ -82,7 +83,7 @@ public class RepositoryIT {
         PlaylistSync sync = PlaylistSync.builder()
                 .name("Playlist1")
                 .syncType(SyncType.INSERT)
-                .ids(Arrays.asList("AAA", "BBB", "CCC"))
+                .ids(Arrays.asList(1L, 2L, 3L))
                 .build();
         playlistSyncRepository.saveAndFlush(sync);
         playlistSyncRepository.deleteById(sync.getId());
diff --git a/mc-vod-sync/mc-vod-sync-app/src/test/resources/testdata-duplicate-video.xlsx b/mc-vod-sync/mc-vod-sync-app/src/test/resources/testdata-duplicate-video.xlsx
new file mode 100644 (file)
index 0000000..5fd759d
Binary files /dev/null and b/mc-vod-sync/mc-vod-sync-app/src/test/resources/testdata-duplicate-video.xlsx differ
index 0a1fe4b73361273afa36b6c95b37dfb016fd1aae..878757101e164d030829fa7439f62a5c59ad1fb4 100644 (file)
@@ -11,6 +11,8 @@ import org.springframework.stereotype.Component;
 @ConfigurationProperties(prefix = "mc-vod-sync.api")
 public class ApiProperties {
 
+    private String baseUrl;
+
     private String tokenRequestUrl;
 
     private String clientId;
index 8d4d4c8dda0f5a9e0568ce5ac6a8f9af83c7a4de..3463f6b1a798c629dc91a71c7e76e84dbbb683b2 100644 (file)
@@ -5,6 +5,7 @@ import com.brightcove.cms.client.api.CustomFieldsApi;
 import com.brightcove.cms.client.api.PlaylistsApi;
 import com.brightcove.cms.client.api.VideosApi;
 import com.brightcove.cms.client.model.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.oltu.oauth2.client.OAuthClient;
@@ -22,30 +23,32 @@ import org.springframework.web.client.HttpClientErrorException;
 import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestClientException;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 
 @Log4j2
 @Service
 public class BrightCoveClient {
+    private final ApiProperties apiProperties;
     private String authToken;
     private long tokenExpires;
 
     public static final String BEARER = "Bearer ";
-    private final ApiClient apiClient = new ExtendedApiClient();
+    private final ApiClient extendedApiClient = new ExtendedApiClient();
     private final PlaylistsApi playListApi = new PlaylistsApi();
     private final VideosApi videosApi = new VideosApi();
     private final CustomFieldsApi customFieldsApi = new CustomFieldsApi();
 
+
     @Autowired
-    private ApiProperties apiProperties;
+    private ObjectMapper objectMapper;
 
-    public BrightCoveClient() {
-        playListApi.setApiClient(apiClient);
-        videosApi.setApiClient(apiClient);
-        customFieldsApi.setApiClient(apiClient);
+    @Autowired
+    public BrightCoveClient(ApiProperties apiProperties) {
+        this.apiProperties = apiProperties;
+        extendedApiClient.setBasePath(apiProperties.getBaseUrl());
+        playListApi.setApiClient(extendedApiClient);
+        videosApi.setApiClient(extendedApiClient);
+        customFieldsApi.setApiClient(extendedApiClient);
     }
 
     private String createToken() {
@@ -134,28 +137,32 @@ public class BrightCoveClient {
         final MultiValueMap<String, String> cookieParams = new LinkedMultiValueMap<String, String>();
         final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
 
-        queryParams.putAll(apiClient.parameterToMultiValueMap(null, "q", query));
+        queryParams.putAll(extendedApiClient.parameterToMultiValueMap(null, "q", query));
 
         if (contentType != null)
-            headerParams.add("Content-Type", apiClient.parameterToString(contentType));
+            headerParams.add("Content-Type", extendedApiClient.parameterToString(contentType));
         if (authorization != null)
-            headerParams.add("Authorization", apiClient.parameterToString(authorization));
+            headerParams.add("Authorization", extendedApiClient.parameterToString(authorization));
 
         final String[] localVarAccepts = {
                 "application/json"
         };
-        final List<MediaType> localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
+        final List<MediaType> localVarAccept = extendedApiClient.selectHeaderAccept(localVarAccepts);
         final String[] contentTypes = {};
-        final MediaType localVarContentType = apiClient.selectHeaderContentType(contentTypes);
+        final MediaType localVarContentType = extendedApiClient.selectHeaderContentType(contentTypes);
 
         String[] authNames = new String[]{"BC_OAuth2"};
 
         ParameterizedTypeReference<PlaylistCount> returnType = new ParameterizedTypeReference<PlaylistCount>() {
         };
-        return apiClient.invokeAPI("/v1/accounts/{account_id}/counts/playlists", HttpMethod.GET, uriVariables, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, authNames, returnType);
+        return extendedApiClient.invokeAPI("/v1/accounts/{account_id}/counts/playlists", HttpMethod.GET, uriVariables, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, authNames, returnType);
     }
 
 
+    public Playlist getPlaylistsById(String id) {
+        return playListApi.getPlaylistById(apiProperties.getAccountId(), id, MediaType.APPLICATION_JSON_VALUE, getToken());
+    }
+
     public Playlist getPlaylistsByName(String name) throws Exception {
         Playlist result = null;
         PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
@@ -277,14 +284,81 @@ public class BrightCoveClient {
         return videosApi.createVideo(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), fields);
     }
 
+    List<String> updatableVideoFields = Arrays.asList("name", "tags", "long_description", "description", "custom_fields");
+
     public Video updateVideo(String videoId, Video video) {
-        return videosApi.updateVideo(apiProperties.getAccountId(), videoId, MediaType.APPLICATION_JSON_VALUE, getToken(), video);
+        final Map<String, Object> videoEx = objectMapper.convertValue(video, objectMapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class));
+        Map<String, Object> filteredVideo = new HashMap<>();
+        updatableVideoFields.forEach(f -> filteredVideo.put(f, videoEx.get(f)));
+        updateVideoWithHttpInfo(apiProperties.getAccountId(), videoId, MediaType.APPLICATION_JSON_VALUE, getToken(), filteredVideo);
+        return getVideoById(videoId);
     }
 
     public void deleteVideo(String id) {
         videosApi.deleteVideo(apiProperties.getAccountId(), "/" + id, MediaType.APPLICATION_JSON_VALUE, getToken());
     }
 
+    //generated function expects Video object, which has prohibited for update fields like variants
+    public ResponseEntity<Map<String, Object>> updateVideoWithHttpInfo(String accountId, String videoId, String contentType, String authorization, Map<String, Object> video) throws RestClientException {
+        Object postBody = video;
+
+        // verify the required parameter 'accountId' is set
+        if (accountId == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'accountId' when calling updateVideo");
+        }
+
+        // verify the required parameter 'videoId' is set
+        if (videoId == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'videoId' when calling updateVideo");
+        }
+
+        // verify the required parameter 'contentType' is set
+        if (contentType == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'contentType' when calling updateVideo");
+        }
+
+        // verify the required parameter 'authorization' is set
+        if (authorization == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'authorization' when calling updateVideo");
+        }
+
+        // verify the required parameter 'video' is set
+        if (video == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'video' when calling updateVideo");
+        }
+
+        // create path and map variables
+        final Map<String, Object> uriVariables = new HashMap<String, Object>();
+        uriVariables.put("account_id", accountId);
+        uriVariables.put("video_id", videoId);
+
+        final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
+        final HttpHeaders headerParams = new HttpHeaders();
+        final MultiValueMap<String, String> cookieParams = new LinkedMultiValueMap<String, String>();
+        final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
+
+        if (contentType != null)
+            headerParams.add("Content-Type", extendedApiClient.parameterToString(contentType));
+        if (authorization != null)
+            headerParams.add("Authorization", extendedApiClient.parameterToString(authorization));
+
+        final String[] localVarAccepts = {
+                "application/json"
+        };
+        final List<MediaType> localVarAccept = extendedApiClient.selectHeaderAccept(localVarAccepts);
+        final String[] contentTypes = {
+                "application/json"
+        };
+        final MediaType localVarContentType = extendedApiClient.selectHeaderContentType(contentTypes);
+
+        String[] authNames = new String[]{"BC_OAuth2"};
+
+        ParameterizedTypeReference<Map<String, Object>> returnType = new ParameterizedTypeReference<Map<String, Object>>() {
+        };
+        return extendedApiClient.invokeAPI("/v1/accounts/{account_id}/videos/{video_id}", HttpMethod.PATCH, uriVariables, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, authNames, returnType);
+    }
+
+
     //generated VideosApi returns Video entity not a List
     private ResponseEntity<List<Video>> getVideoByIdOrReferenceIdWithHttpInfo(String accountId, String videoIds, String contentType, String authorization, Boolean includeVariants) throws RestClientException {
         Object postBody = null;
index c0eae3c667c2a9fad6346a0e391ac015caaaf10c..9b855d7f9428c534592f1f371cab72e566c95c31 100644 (file)
@@ -1,7 +1,3 @@
 -- // Bootstrap.sql
 -- DROP DATABASE IF EXISTS VODSYNC;
--- CREATE DATABASE VODSYNC AUTOMATIC STORAGE YES USING CODESET UTF-8 TERRITORY hu COLLATE USING UCA500R1_S2 PAGESIZE 32 K;
-
-TRUNCATE TABLE asset IMMEDIATE;
-TRUNCATE TABLE asset_sync IMMEDIATE;
-TRUNCATE TABLE playlist_sync IMMEDIATE;
+-- CREATE DATABASE VODSYNC USING CODESET UTF-8 TERRITORY hu catalog tablespace managed by system using ('catalog_TS') user tablespace managed by system using ('data_TS') temporary tablespace managed by system using ('temporary_TS');
index ec2ddfdff98a682f7da6927621eb505c4b3fd09c..0d5194d38809c5cad5fec64a110afff634aa5392 100644 (file)
@@ -11,17 +11,20 @@ CREATE TABLE upload_file (
 );
 
 CREATE TABLE asset (
+    id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
     catalog_id VARCHAR(20) NOT NULL,
     reference_id VARCHAR(20),
     season_id BIGINT NOT NULL,
     series_id BIGINT NOT NULL,
     sunset DATE NOT NULL,
     sunrise DATE NOT NULL,
-    playlist VARCHAR(100) NOT NULL,
-    hub_info VARCHAR(100),
-    prog_local_title VARCHAR(255) NOT NULL,
-    season_local_title VARCHAR(255),
-    series_local_title VARCHAR(255),
+    playlist VARCHAR(255) NOT NULL,
+    hub_info VARCHAR(128),
+    prog_local_title VARCHAR(250) NOT NULL,
+    prog_synopsis_short_hun VARCHAR(250),
+    prog_synopsis_full_hun VARCHAR(5000),
+    season_local_title VARCHAR(128),
+    series_local_title VARCHAR(128),
     season_nr INTEGER,
     episode_nr INTEGER,
     production_year INTEGER,
@@ -30,12 +33,18 @@ CREATE TABLE asset (
     content_type VARCHAR(50),
     content_source VARCHAR(50),
     age_rating VARCHAR(10),
-    CONSTRAINT pk_catalog_id PRIMARY KEY (catalog_id)
+    director VARCHAR(128),
+    x_cast VARCHAR(128),
+    prog_genre1 VARCHAR(128),
+    prog_genre2 VARCHAR(128),
+    prog_genre3 VARCHAR(128),
+    CONSTRAINT pk_asset PRIMARY KEY (id)
 );
 CREATE INDEX idx_asset_playlist ON asset(playlist);
 
 CREATE TABLE asset_sync (
     id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    asset_id BIGINT,
     catalog_id VARCHAR(20) NOT NULL,
     created TIMESTAMP NOT NULL,
     sync_type VARCHAR(6) NOT NULL,
@@ -47,7 +56,7 @@ CREATE INDEX idx_asset_sync_exported_success ON asset_sync(exported_success);
 
 CREATE TABLE playlist_sync (
     id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    name VARCHAR(100) NOT NULL,
+    name VARCHAR(255) NOT NULL,
     created TIMESTAMP NOT NULL,
     sync_type VARCHAR(6) NOT NULL,
     exported_success TIMESTAMP,
index 5290e0615d21201bdfd9584d17b8f62a72f10acc..e97ceddba9a9b91a73378ba7d6776e56b52d28a9 100644 (file)
@@ -2,9 +2,7 @@ package hu.user.mcvodsync.db;
 
 import lombok.*;
 
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
+import javax.persistence.*;
 import java.io.Serializable;
 import java.sql.Date;
 
@@ -17,6 +15,9 @@ import java.sql.Date;
 @AllArgsConstructor
 public class Asset implements Serializable {
     @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
     private String catalogId;
 
     private Long seasonId;
@@ -34,13 +35,22 @@ public class Asset implements Serializable {
     @Column(nullable = false)
     private String playlist;
 
+    @Column(length = 128)
     private String hubInfo;
 
-    @Column(nullable = false)
+    @Column(nullable = false, length = 250)
     private String progLocalTitle;
 
+    @Column(length = 250)
+    private String progSynopsisShortHun;
+
+    @Column(length = 5000)
+    private String progSynopsisFullHun;
+
+    @Column(length = 128)
     private String seasonLocalTitle;
 
+    @Column(length = 128)
     private String seriesLocalTitle;
 
     private Integer seasonNr;
@@ -58,4 +68,20 @@ public class Asset implements Serializable {
     private String contentSource;
 
     private String ageRating;
+
+    @Column(length = 128)
+    private String director;
+
+    @Column(length = 128)
+    private String xCast;
+
+    @Column(name = "prog_genre1", length = 128)
+    private String progGenre1;
+
+    @Column(name = "prog_genre2", length = 128)
+    private String progGenre2;
+
+    @Column(name = "prog_genre3", length = 128)
+    private String progGenre3;
+
 }
index 1790880366e7a65b2b3f7d3ed0efa54d9cd7eb48..6dda3bb0cd354c4fea29e65b9a8301d229e9b042 100644 (file)
@@ -17,7 +17,9 @@ import java.util.Date;
 public class AssetSync implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    Long id;
+    private Long id;
+
+    private Long assetId;
 
     private String catalogId;
 
index 9cbf6357332121da1b021e7e7868b95a2a32d765..8b4fda85d7bb375ae628783a18ca3f24dd7a5c68 100644 (file)
@@ -17,9 +17,9 @@ import java.io.Serializable;
 public class Associate implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    Long id;
-    String name;
-    String login;
-    String password;
-    boolean active;
+    private Long id;
+    private String name;
+    private String login;
+    private String password;
+    private boolean active;
 }
index 6e18d534f9fabc583764fe04dd363899a2a2b55b..fa2f8f752a66b61fd1f7f72f3dcb2a278759ebf3 100644 (file)
@@ -19,7 +19,7 @@ import java.util.List;
 public class PlaylistSync implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    Long id;
+    private Long id;
 
     private String name;
 
@@ -36,5 +36,5 @@ public class PlaylistSync implements Serializable {
     private Date exportedError;
 
     @Convert(converter = StringListConverter.class)
-    private List<String> ids;
+    private List<Long> ids;
 }
index fc45d34420f18ade16d660e7c7884c75406367a7..2b326d15adc0c45085bc093e82394228a1f6da54 100644 (file)
@@ -16,15 +16,15 @@ import java.util.Date;
 public class UploadFile implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    Long id;
+    private Long id;
 
     @CreationTimestamp
     @Column(updatable = false)
-    Date created;
+    private Date created;
 
-    String name;
+    private String name;
 
-    int size;
+    private int size;
 
-    byte[] file;
+    private byte[] file;
 }
index b30d2638b08a310b10e42922cb9079f844f6ff02..28bc89520da5afa7f2d9bd1592be1539b1961125 100644 (file)
@@ -5,19 +5,28 @@ import javax.persistence.Converter;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 @Converter
-public class StringListConverter implements AttributeConverter<List<String>, byte[]> {
+public class StringListConverter implements AttributeConverter<List<Long>, byte[]> {
     private static final String SPLIT_CHAR = ",";
 
     @Override
-    public byte[] convertToDatabaseColumn(List<String> dataList) {
-        return Objects.isNull(dataList) ? null : String.join(SPLIT_CHAR, dataList).getBytes();
+    public byte[] convertToDatabaseColumn(List<Long> ids) {
+        if (Objects.isNull(ids) || ids.isEmpty()) {
+            return null;
+        }
+        List<String> converted = ids.stream().map(String::valueOf).collect(Collectors.toList());
+        return String.join(SPLIT_CHAR, converted).getBytes();
     }
 
     @Override
-    public List<String> convertToEntityAttribute(byte[] data) {
+    public List<Long> convertToEntityAttribute(byte[] data) {
+        if (data == null) {
+            return null;
+        }
         String stringData = new String(data);
-        return Arrays.asList(stringData.split(SPLIT_CHAR));
+        List<String> ids = Arrays.asList(stringData.split(SPLIT_CHAR));
+        return ids.stream().map(Long::parseLong).collect(Collectors.toList());
     }
 }
\ No newline at end of file
index 37c8e74cf1ff4026864437842d023544db9917d9..cec95118d603feaf6467ec73c7ee851c0e10246e 100644 (file)
@@ -7,25 +7,31 @@ import org.springframework.data.jpa.repository.Query;
 
 import java.sql.Date;
 import java.util.List;
+import java.util.Optional;
 
-public interface AssetRepository extends JpaRepository<Asset, String> {
+public interface AssetRepository extends JpaRepository<Asset, Long> {
 
     @Query("SELECT DISTINCT(a.playlist) FROM Asset a ORDER BY a.playlist")
     List<String> queryDistinctPlaylists();
 
-    @Query("SELECT a.catalogId FROM Asset a WHERE a.playlist = :playlist ORDER BY a.seasonNr, a.episodeNr")
-    List<String> queryPlaylistsAssets(String playlist);
+    @Query("SELECT a.id FROM Asset a WHERE a.playlist = :playlist ORDER BY a.seasonNr, a.episodeNr")
+    List<Long> queryPlaylistsAssets(String playlist);
 
-    @Query("SELECT a.catalogId FROM Asset a WHERE a.sunset <= :currentDate ORDER BY a.catalogId")
-    List<String> queryExpired(Date currentDate);
+    Optional<Asset> findByCatalogIdAndPlaylist(String catalogId, String playlist);
+
+    @Query("SELECT a FROM Asset a WHERE a.sunset <= :currentDate ORDER BY a.catalogId")
+    List<Asset> queryExpired(Date currentDate);
 
     @Modifying
     @Query("DELETE FROM Asset a WHERE a.sunset <= :currentDate")
     void deleteExpired(Date currentDate);
 
-    @Query("SELECT a.referenceId FROM Asset a WHERE a.catalogId = :catalogId")
-    String findReferenceIdByCatalogId(String catalogId);
+    @Query("SELECT a.referenceId FROM Asset a WHERE a.id = :id")
+    String findReferenceIdById(Long id);
+
+    @Query("SELECT a.catalogId FROM Asset a WHERE a.id = :id")
+    String findCatalogIdById(Long id);
 
-    @Query("SELECT a.catalogId FROM Asset a WHERE a.referenceId = :referenceId")
-    String findCatalogIdByReferenceId(String referenceId);
+    @Query("SELECT a.id FROM Asset a WHERE a.referenceId = :referenceId AND a.playlist = :playlist")
+    String findIdByReferenceId(String referenceId, String playlist);
 }
index df29c9f97865eaffcf5cabe0da100e2681272d18..0807297244d8ce88e11ccd5cae48237868eddc0b 100644 (file)
@@ -11,6 +11,8 @@ public interface AssetSyncRepository extends JpaRepository<AssetSync, String> {
 
     long countBySyncType(SyncType syncType);
 
+    long countByExportedSuccessIsNull();
+
     @Query("SELECT a.id FROM AssetSync a WHERE a.exportedSuccess IS NULL ORDER BY a.created")
     List<Long> queryIdsForExport();
 
index ff65fb39797b9b973c154c536313f15327c106d9..57c88a8aca92088506fe8a23eec19273396d893f 100644 (file)
@@ -11,6 +11,8 @@ public interface PlaylistSyncRepository extends JpaRepository<PlaylistSync, Long
 
     long countBySyncType(SyncType syncType);
 
+    long countByExportedSuccessIsNull();
+
     List<PlaylistSync> findAllByName(String name);
 
     @Query("SELECT p.id FROM PlaylistSync p WHERE p.exportedSuccess IS NULL ORDER BY p.created")
index 3cd7c29d26ff7ef754274153ab1274a962bc56d2..515b3e15f8cb1270b0062dadc17d37001ad3579c 100644 (file)
@@ -16,6 +16,7 @@ public class ServiceProperties {
     private boolean targetPlaylistInsertEnabled;
 
     private Scheduler scheduler;
+    private Report report;
 
     @Getter
     @Setter
@@ -29,8 +30,16 @@ public class ServiceProperties {
 
         private String exportCron;
 
-        private boolean sunriseCheckerEnabled;
+        private boolean sunsetCheckerEnabled;
+
+        private String sunsetCheckerCron;
+    }
+
+    @Getter
+    @Setter
+    public static final class Report {
+        private String sender;
+        private String recipient;
 
-        private String sunriseCheckerCron;
     }
 }
index 6746aa9d9d20706b324539404bf232eaf19aa10f..4a8ffdd9231e2311d6d55700cb61f499f692bad5 100644 (file)
@@ -1,12 +1,18 @@
 package hu.user.mcvodsync.service.config;
 
+import hu.user.mcvodsync.db.repository.AssetSyncRepository;
+import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
 import hu.user.mcvodsync.service.ServiceProperties;
+import hu.user.mcvodsync.service.data.CompositeSummary;
+import hu.user.mcvodsync.service.event.ExportCompletedEvent;
+import hu.user.mcvodsync.service.event.ExportStartedEvent;
 import hu.user.mcvodsync.service.event.ImportCompletedEvent;
 import hu.user.mcvodsync.service.event.ImportStartedEvent;
-import hu.user.mcvodsync.service.in.ImportSummary;
+import hu.user.mcvodsync.service.mail.EmailSendService;
 import hu.user.mcvodsync.service.schedule.ScheduledExport;
 import hu.user.mcvodsync.service.schedule.ScheduledImport;
-import hu.user.mcvodsync.service.schedule.ScheduledSunriseChacker;
+import hu.user.mcvodsync.service.schedule.ScheduledSunsetChacker;
+import hu.user.mcvodsync.service.time.TimeUtils;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,14 +42,29 @@ public class ScheduledTasks {
     private ScheduledImport scheduledImport;
 
     @Autowired
-    private ScheduledSunriseChacker scheduledSunriseChacker;
+    private ScheduledSunsetChacker scheduledSunsetChacker;
+
+    @Autowired
+    private AssetSyncRepository assetSyncRepository;
+
+    @Autowired
+    private PlaylistSyncRepository playlistSyncRepository;
+
+    @Autowired
+    EmailSendService emailSendService;
 
     @Getter
-    private ImportSummary importSummary;
+    private CompositeSummary importSummary;
+
+    @Getter
+    private CompositeSummary exportSummary;
 
     @Getter
     private String status;
 
+    @Getter
+    private boolean outOfSync;
+
     @PostConstruct
     public void scheduleTasks() {
         //new CronTrigger("0 0 4 1/1 * ? *")
@@ -56,9 +77,11 @@ public class ScheduledTasks {
         if (scheduler.isImportEnabled()) {
             taskScheduler.schedule(scheduledImport, new CronTrigger(scheduler.getExportCron()));
         }
-        if (scheduler.isSunriseCheckerEnabled()) {
-            taskScheduler.schedule(scheduledSunriseChacker, new CronTrigger(scheduler.getSunriseCheckerCron()));
+        if (scheduler.isSunsetCheckerEnabled()) {
+            taskScheduler.schedule(scheduledSunsetChacker, new CronTrigger(scheduler.getSunsetCheckerCron()));
         }
+
+        checkSyncStatus();
     }
 
 
@@ -75,7 +98,7 @@ public class ScheduledTasks {
     public void handleEvent(ImportStartedEvent evt) {
         log.info("ImportStartedEvent handle");
         importSummary = null;
-        status = String.format("Import from %s started", evt.getFileName());
+        status = String.format("Import from %s is in progress, started as %s", evt.getFileName(), TimeUtils.toString(evt.getTimestamp()));
     }
 
     @Async
@@ -83,6 +106,38 @@ public class ScheduledTasks {
     public void handleEvent(ImportCompletedEvent evt) {
         log.info("ImportCompletedEvent handle");
         importSummary = evt.getSummary();
-        status = "Import completed";
+        status = String.format("Import completed at %s", TimeUtils.toString(evt.getTimestamp()));
+        checkSyncStatus();
+        emailSendService.sendSimpleMessage("BrightCove import report", importSummary);
+    }
+
+    @Async
+    @EventListener
+    public void handleEvent(ExportStartedEvent evt) {
+        log.info("ExportStartedEvent handle");
+        exportSummary = null;
+        status = String.format("Export is in progress, started at %s", TimeUtils.toString(evt.getTimestamp()));
+    }
+
+    @Async
+    @EventListener
+    public void handleEvent(ExportCompletedEvent evt) {
+        log.info("ExportCompletedEvent handle");
+        exportSummary = evt.getSummary();
+        status = String.format("Export completed at %s", TimeUtils.toString(evt.getTimestamp()));
+        checkSyncStatus();
+        emailSendService.sendSimpleMessage("BrightCove export report", importSummary);
+    }
+
+    public void reset() {
+        importSummary = null;
+        exportSummary = null;
+        checkSyncStatus();
+    }
+
+
+    public void checkSyncStatus() {
+        outOfSync = assetSyncRepository.countByExportedSuccessIsNull() > 0
+                || playlistSyncRepository.countByExportedSuccessIsNull() > 0;
     }
 }
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/CompositeSummary.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/CompositeSummary.java
new file mode 100644 (file)
index 0000000..55017fc
--- /dev/null
@@ -0,0 +1,56 @@
+package hu.user.mcvodsync.service.data;
+
+import hu.user.mcvodsync.service.time.TimeUtils;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DurationFormatUtils;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Objects;
+
+@Getter
+@Setter
+@Builder
+public class CompositeSummary {
+    @Builder.Default
+    private Summary video = Summary.builder().build();
+
+    @Builder.Default
+    private Summary playlist = Summary.builder().build();
+
+    private Instant started;
+
+    private Instant finished;
+
+    public String toString() {
+        return String.format("Execution started at %s, finished at %s.", getStartedFormatted(), getFinishedFormatted()) +
+                System.lineSeparator() +
+                String.format("Process execution took %s, processed %d videos and %d playlists.", getDuration(), video.getAll(), playlist.getAll()) +
+                System.lineSeparator() +
+                String.format("Video success count: %d, error count: %d, skip count: %d", video.getSuccess(), video.getError(), video.getSkip()) +
+                System.lineSeparator() +
+                String.format("Video insert count: %d, update count: %d, delete count: %d", video.getInsert(), video.getUpdate(), video.getDelete()) +
+                System.lineSeparator() +
+                String.format("Playlist success count: %d, error count: %d, skip count: %d", playlist.getSuccess(), playlist.getError(), playlist.getSkip()) +
+                System.lineSeparator() +
+                String.format("Playlist insert count: %d, update count: %d, delete count: %d", playlist.getInsert(), playlist.getUpdate(), playlist.getDelete());
+    }
+
+    public String getDuration() {
+        Duration executionDuration = Duration.between(started, finished);
+        return DurationFormatUtils.formatDuration(executionDuration.toMillis(), "H:mm:ss", true);
+    }
+
+    public String getStartedFormatted() {
+        return Objects.isNull(started) ? StringUtils.EMPTY : TimeUtils.toString(started.toEpochMilli());
+    }
+
+    public String getFinishedFormatted() {
+        return Objects.isNull(finished) ? StringUtils.EMPTY : TimeUtils.toString(finished.toEpochMilli());
+    }
+
+
+}
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/Summary.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/data/Summary.java
new file mode 100644 (file)
index 0000000..f957233
--- /dev/null
@@ -0,0 +1,53 @@
+package hu.user.mcvodsync.service.data;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Builder
+public class Summary {
+    private long all;
+
+    private long success;
+
+    private long error;
+
+    private long skip;
+
+    private long insert;
+
+    private long update;
+
+    private long delete;
+
+    public void incAll() {
+        all++;
+    }
+
+    public void incSuccess() {
+        success++;
+    }
+
+    public void incError() {
+        error++;
+    }
+
+    public void incSkip() {
+        skip++;
+    }
+
+    public void incInsert() {
+        insert++;
+    }
+
+    public void incUpdate() {
+        update++;
+    }
+
+    public void incDelete() {
+        update++;
+    }
+
+}
index 95c7a623545711e9ef3dd710f6bd83cf14cced92..c0639c97b459d2f3320c5a8b225cc617adfd08d8 100644 (file)
@@ -1,6 +1,6 @@
 package hu.user.mcvodsync.service.event;
 
-import hu.user.mcvodsync.service.in.ImportSummary;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import lombok.Getter;
 import lombok.Setter;
 import org.springframework.context.ApplicationEvent;
@@ -9,9 +9,9 @@ import org.springframework.context.ApplicationEvent;
 @Setter
 public class ExportCompletedEvent extends ApplicationEvent {
 
-    private final ImportSummary summary;
+    private final CompositeSummary summary;
 
-    public ExportCompletedEvent(ImportSummary summary, Object source) {
+    public ExportCompletedEvent(Object source, CompositeSummary summary) {
         super(source);
         this.summary = summary;
     }
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportStartedEvent.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportStartedEvent.java
new file mode 100644 (file)
index 0000000..7f0048b
--- /dev/null
@@ -0,0 +1,15 @@
+package hu.user.mcvodsync.service.event;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@Setter
+public class ExportStartedEvent extends ApplicationEvent {
+
+    public ExportStartedEvent(Object source) {
+        super(source);
+    }
+
+}
index 1ef84d9520d7e8aabd93221035bbc5dce0591c0b..374e1d11db5e791ab6bc714e7b391a6d6fb1cc64 100644 (file)
@@ -1,6 +1,6 @@
 package hu.user.mcvodsync.service.event;
 
-import hu.user.mcvodsync.service.in.ImportSummary;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import lombok.Getter;
 import lombok.Setter;
 import org.springframework.context.ApplicationEvent;
@@ -9,9 +9,9 @@ import org.springframework.context.ApplicationEvent;
 @Setter
 public class ImportCompletedEvent extends ApplicationEvent {
 
-    private final ImportSummary summary;
+    private final CompositeSummary summary;
 
-    public ImportCompletedEvent(Object source, ImportSummary summary) {
+    public ImportCompletedEvent(Object source, CompositeSummary summary) {
         super(source);
         this.summary = summary;
     }
index 9e656bf970cbcd4c22be9ace1ff0bcd62640dbc4..2fd8ca519cd5279714af29c8ddd9b732de2f1d31 100644 (file)
@@ -8,6 +8,7 @@ import hu.user.mcvodsync.db.SyncType;
 import hu.user.mcvodsync.db.repository.AssetRepository;
 import hu.user.mcvodsync.db.repository.AssetSyncRepository;
 import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import hu.user.mcvodsync.service.data.EntityDataService;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.collections4.CollectionUtils;
@@ -34,33 +35,33 @@ public class AssetImportService {
     @Autowired
     private EntityDataService<Asset> entityDataService;
 
-    private Map<String, List<String>> currentPlaylists;
+    private Map<String, List<Long>> currentPlaylists;
 
-    private ImportSummary summary;
 
-    public void prepare(ImportSummary summary) {
-        this.summary = summary;
+    public void prepare() {
         currentPlaylists = getPlayLists();
     }
 
-    public Map<String, List<String>> getPlayLists() {
-        Map<String, List<String>> result = new HashMap<>();
+    public Map<String, List<Long>> getPlayLists() {
+        Map<String, List<Long>> result = new HashMap<>();
         List<String> playlistNames = assetRepository.queryDistinctPlaylists();
         playlistNames.forEach(playlist -> {
-            List<String> playlistsAssets = assetRepository.queryPlaylistsAssets(playlist);
+            List<Long> playlistsAssets = assetRepository.queryPlaylistsAssets(playlist);
             result.put(playlist, playlistsAssets);
         });
         return result;
     }
 
-    public void processAsset(Asset asset) {
-        Optional<Asset> optionalEntity = assetRepository.findById(asset.getCatalogId());
+    public void processAsset(Asset asset, CompositeSummary summary) {
+        Optional<Asset> optionalEntity = assetRepository.findByCatalogIdAndPlaylist(asset.getCatalogId(), asset.getPlaylist());
 
         AssetSync assetSync = AssetSync.builder()
                 .catalogId(asset.getCatalogId())
                 .build();
 
         if (optionalEntity.isPresent()) {
+            asset.setId(optionalEntity.get().getId());
+            asset.setReferenceId(optionalEntity.get().getReferenceId());
             boolean areDifferent = entityDataService.areDifferent(asset, optionalEntity.get());
             if (areDifferent) {
                 assetSync.setSyncType(SyncType.UPDATE);
@@ -69,37 +70,46 @@ public class AssetImportService {
             assetSync.setSyncType(SyncType.INSERT);
         }
 
-        if (Objects.nonNull(assetSync.getSyncType())) {
-            assetRepository.saveAndFlush(asset);
-            assetSyncRepository.saveAndFlush(assetSync);
-        }
+        if (new Date().after(asset.getSunset())) {
+            summary.getVideo().incSkip();
+            if (assetSync.getSyncType() == SyncType.UPDATE) {
+                assetRepository.saveAndFlush(asset);
+            }
+        } else {
+            if (Objects.nonNull(assetSync.getSyncType())) {
+                assetRepository.saveAndFlush(asset);
+                assetSync.setAssetId(asset.getId());
+                assetSyncRepository.saveAndFlush(assetSync);
+            }
 
-        if (assetSync.getSyncType() == SyncType.UPDATE) {
-            summary.incUpdated();
-        }
-        if (assetSync.getSyncType() == SyncType.INSERT) {
-            summary.incInserted();
+            if (assetSync.getSyncType() == SyncType.UPDATE) {
+                summary.getVideo().incUpdate();
+            }
+            if (assetSync.getSyncType() == SyncType.INSERT) {
+                summary.getVideo().incInsert();
+            }
         }
     }
 
-    public void removeExpired(LocalDate currentDate) {
-        List<String> ids = assetRepository.queryExpired(java.sql.Date.valueOf(currentDate));
+    public void removeExpired(LocalDate currentDate, CompositeSummary summary) {
+        List<Asset> expiredAssets = assetRepository.queryExpired(java.sql.Date.valueOf(currentDate));
         assetRepository.deleteExpired(java.sql.Date.valueOf(currentDate));
-        List<AssetSync> syncs = ids.stream().map(id -> AssetSync.builder()
-                .catalogId(id)
+        List<AssetSync> syncs = expiredAssets.stream().map(asset -> AssetSync.builder()
+                .assetId(asset.getId())
+                .catalogId(asset.getCatalogId())
                 .syncType(SyncType.DELETE)
                 .build()).collect(Collectors.toList());
         assetSyncRepository.saveAllAndFlush(syncs);
-        summary.setDeleted(summary.getDeleted() + ids.size());
+        summary.getVideo().setDelete(summary.getVideo().getDelete() + expiredAssets.size());
     }
 
-    public void finish() {
-        removeExpired(LocalDate.now());
-        processPlaylists();
+    public void finish(CompositeSummary summary) {
+        removeExpired(LocalDate.now(), summary);
+        processPlaylists(summary);
     }
 
-    public void processPlaylists() {
-        Map<String, List<String>> newPlaylists = getPlayLists();
+    public void processPlaylists(CompositeSummary summary) {
+        Map<String, List<Long>> newPlaylists = getPlayLists();
         Set<String> currentPlaylistNames = currentPlaylists.keySet();
         Set<String> newPlaylistNames = newPlaylists.keySet();
 
@@ -112,7 +122,7 @@ public class AssetImportService {
                         .created(Date.from(Instant.now()))
                         .build();
                 playlistSyncRepository.save(sync);
-                summary.incDeletedPlaylist();
+                summary.getPlaylist().incDelete();
             });
         }
 
@@ -126,13 +136,13 @@ public class AssetImportService {
                         .ids(newPlaylists.get(name))
                         .build();
                 playlistSyncRepository.save(sync);
-                summary.incInsertedPlaylist();
+                summary.getPlaylist().incInsert();
             });
         }
 
         currentPlaylistNames.forEach(name -> {
-            List<String> currentContent = currentPlaylists.get(name);
-            List<String> newContent = newPlaylists.get(name);
+            List<Long> currentContent = currentPlaylists.get(name);
+            List<Long> newContent = newPlaylists.get(name);
             if (isContentChanged(currentContent, newContent)) {
                 PlaylistSync sync = PlaylistSync.builder()
                         .name(name)
@@ -141,12 +151,12 @@ public class AssetImportService {
                         .created(Date.from(Instant.now()))
                         .build();
                 playlistSyncRepository.save(sync);
-                summary.incUpdatedPlaylist();
+                summary.getPlaylist().incUpdate();
             }
         });
     }
 
-    private boolean isContentChanged(List<String> currentContent, List<String> newContent) {
+    private boolean isContentChanged(List<Long> currentContent, List<Long> newContent) {
         if (currentContent.size() != newContent.size()) {
             return true;
         }
index 85f616b38672be36e229b3fbc7a06956dd9ac586..9cf46c0792941869dd58dabf2707013754b05958 100644 (file)
@@ -24,6 +24,8 @@ public interface AssetMapper {
     @Mapping(target = "playlist", source = "PLAYLIST_NAME")
     @Mapping(target = "hubInfo", source = "HUB_INFO")
     @Mapping(target = "progLocalTitle", source = "PROG_LOCAL_TITLE")
+    @Mapping(target = "progSynopsisShortHun", source = "PROG_SYNOPSIS_SHORT_HUN")
+    @Mapping(target = "progSynopsisFullHun", source = "PROG_SYNOPSIS_FULL_HUN")
     @Mapping(target = "seasonLocalTitle", source = "SEASON_LOCAL_TITLE")
     @Mapping(target = "seriesLocalTitle", source = "SERIES_GROUP_LOCAL_TITLE")
     @Mapping(target = "seasonNr", source = "SEASON_NUMBER", qualifiedByName = "mapNullableNumber")
@@ -34,6 +36,11 @@ public interface AssetMapper {
     @Mapping(target = "contentType", source = "CONTENT_TYPE")
     @Mapping(target = "contentSource", source = "CONTENT_SOURCE")
     @Mapping(target = "ageRating", source = "AGE_RATING")
+    @Mapping(target = "director", source = "DIRECTOR")
+    @Mapping(target = "xCast", source = "X_CAST")
+    @Mapping(target = "progGenre1", source = "PROG_GENRE_1")
+    @Mapping(target = "progGenre2", source = "PROG_GENRE_2")
+    @Mapping(target = "progGenre3", source = "PROG_GENRE_3")
     Asset toEntity(Map<String, String> xlsRowData);
 
     @Named("mapNullableNumber")
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/ImportSummary.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/in/ImportSummary.java
deleted file mode 100644 (file)
index d5fbf36..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-package hu.user.mcvodsync.service.in;
-
-import lombok.Builder;
-import lombok.Getter;
-import lombok.Setter;
-import org.apache.commons.lang3.time.DurationFormatUtils;
-
-import java.time.Duration;
-import java.time.Instant;
-
-@Getter
-@Setter
-@Builder
-public class ImportSummary {
-    private Instant started;
-
-    private Instant finished;
-
-    private long all;
-
-    private long success;
-
-    private long error;
-
-    private long inserted;
-
-    private long updated;
-
-    private long deleted;
-
-    private long insertedPlaylist;
-
-    private long updatedPlaylist;
-
-    private long deletedPlaylist;
-
-    public String toString() {
-        Duration executionDuration = Duration.between(started, finished);
-        String duration = DurationFormatUtils.formatDuration(executionDuration.toMillis(), "H:mm:ss", true);
-        return String.format("Execution started at %s, finished at %s.", started, finished) +
-                System.lineSeparator() +
-                String.format("Process execution took %s on %d rows.", duration, all) +
-                System.lineSeparator() +
-                String.format("Success count: %d, error count: %d", success, error) +
-                System.lineSeparator() +
-                String.format("Insert count: %d, update count: %d, delete count: %d", inserted, updated, deleted);
-    }
-
-    public void incAll() {
-        all++;
-    }
-
-    public void incSuccess() {
-        success++;
-    }
-
-    public void incError() {
-        error++;
-    }
-
-    public void incInserted() {
-        inserted++;
-    }
-
-    public void incUpdated() {
-        updated++;
-    }
-
-    public void incInsertedPlaylist() {
-        insertedPlaylist++;
-    }
-
-    public void incUpdatedPlaylist() {
-        updatedPlaylist++;
-    }
-
-    public void incDeletedPlaylist() {
-        deletedPlaylist++;
-    }
-
-}
index 9ccc5bcfcf482e462d32a92cf5474c49b43de64b..b2e7fa99dc2bfebab65f23973734ea83582718c3 100644 (file)
@@ -1,6 +1,7 @@
 package hu.user.mcvodsync.service.in;
 
 import hu.user.mcvodsync.db.Asset;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
 import org.dhatim.fastexcel.reader.Cell;
@@ -8,7 +9,7 @@ import org.dhatim.fastexcel.reader.ReadableWorkbook;
 import org.dhatim.fastexcel.reader.Row;
 import org.dhatim.fastexcel.reader.Sheet;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.ByteArrayInputStream;
@@ -23,7 +24,7 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 @Log4j2
-@Service
+@Component
 public class VodXlsProcessor {
     private List<Cell> headers;
 
@@ -33,24 +34,26 @@ public class VodXlsProcessor {
     @Autowired
     private AssetImportService assetImportService;
 
+
     @Transactional
-    public ImportSummary process(String fileName, byte[] xlsData) {
-        ImportSummary summary = ImportSummary.builder().started(Instant.now()).build();
+    public CompositeSummary process(String fileName, byte[] xlsData) {
+        CompositeSummary summary = CompositeSummary.builder().started(Instant.now()).build();
         try (InputStream is = new ByteArrayInputStream(xlsData);
              ReadableWorkbook wb = new ReadableWorkbook(is)) {
             Sheet sheet = wb.getFirstSheet();
             try (Stream<Row> rows = sheet.openStream()) {
                 rows.forEach(row -> {
                     if (row.getRowNum() == 1) {
-                        assetImportService.prepare(summary);
+                        assetImportService.prepare();
                         headers = getHeaders(row);
                     } else {
-                        summary.incAll();
+                        log.info("Processing {}", row.getRowNum());
+                        summary.getVideo().incAll();
                         processRow(row, summary);
                     }
                 });
             }
-            assetImportService.finish();
+            assetImportService.finish(summary);
 
         } catch (IOException e) {
             log.error("Excel file reading error from {}. System message: {}", fileName, e.getMessage());
@@ -64,7 +67,7 @@ public class VodXlsProcessor {
         return row.stream().collect(Collectors.toList());
     }
 
-    private void processRow(Row r, ImportSummary summary) {
+    private void processRow(Row r, CompositeSummary summary) {
         Map<String, String> rowData = new HashMap<>();
         r.stream().filter(Objects::nonNull).forEach(c -> {
             try {
@@ -80,11 +83,13 @@ public class VodXlsProcessor {
         try {
             asset = assetMapper.toEntity(rowData);
             if (isAssetValid(asset)) {
-                assetImportService.processAsset(asset);
+                assetImportService.processAsset(asset, summary);
+            } else {
+                summary.getVideo().incSkip();
             }
-            summary.incSuccess();
+            summary.getVideo().incSuccess();
         } catch (Exception e) {
-            summary.incError();
+            summary.getVideo().incError();
             log.error("Processing error for {}", asset, e);
         }
     }
index 2eacce9029775a6a60c943ee4a81e583f5039395..ca0472bdafd67a0843a120ba780de49ef16b0742 100644 (file)
@@ -1,23 +1,42 @@
 package hu.user.mcvodsync.service.mail;
 
+import hu.user.mcvodsync.service.ServiceProperties;
+import hu.user.mcvodsync.service.data.CompositeSummary;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.stereotype.Service;
 
+import java.util.Objects;
+
+@Log4j2
 @Service
 public class EmailSendService {
     //    https://www.baeldung.com/spring-email
-    @Autowired
+    @Autowired(required = false)
     private JavaMailSender emailSender;
 
-    public void sendSimpleMessage() {
+    @Autowired
+    private ServiceProperties serviceProperties;
+
+    public void sendSimpleMessage(String subject, CompositeSummary summary) {
+        if (Objects.isNull(emailSender)) {
+            log.warn("Missing email settings, can not initiate JavaMailSender");
+            return;
+        }
+        if (StringUtils.isBlank(serviceProperties.getReport().getRecipient())) {
+            log.info("No recipient specified, report not sent.");
+            return;
+        }
         SimpleMailMessage message = new SimpleMailMessage();
-        message.setFrom("noreply@useribm.hu");
-        message.setTo("vasary@elgekko.net");
-        message.setSubject("Teszt");
-        message.setText("Teszt1");
+        message.setFrom(serviceProperties.getReport().getSender());
+        message.setTo(serviceProperties.getReport().getRecipient());
+        message.setSubject(subject);
+        message.setText(summary.toString());
         emailSender.send(message);
+        log.info("'{}' report sent to {}", subject, serviceProperties.getReport().getRecipient());
     }
 }
 
similarity index 62%
rename from mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/AssetExportService.java
rename to mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/SyncExportService.java
index 335e1ea15177615ede446f412ee65de9c25a8d59..31390b379c65412fc35f1620da9c0a41e52c77a3 100644 (file)
@@ -3,7 +3,6 @@ package hu.user.mcvodsync.service.out;
 
 import com.brightcove.cms.client.model.Playlist;
 import com.brightcove.cms.client.model.Video;
-import com.google.common.collect.Lists;
 import hu.user.mcvodsync.brightcove.BrightCoveClient;
 import hu.user.mcvodsync.db.Asset;
 import hu.user.mcvodsync.db.AssetSync;
@@ -12,7 +11,7 @@ import hu.user.mcvodsync.db.SyncType;
 import hu.user.mcvodsync.db.repository.AssetRepository;
 import hu.user.mcvodsync.db.repository.AssetSyncRepository;
 import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
-import hu.user.mcvodsync.service.ServiceProperties;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,7 +20,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.persistence.EntityNotFoundException;
 import java.time.Instant;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
@@ -29,7 +27,7 @@ import java.util.stream.Collectors;
 
 @Log4j2
 @Service
-public class AssetExportService {
+public class SyncExportService {
     @Autowired
     private BrightCoveClient bcClient;
 
@@ -45,160 +43,160 @@ public class AssetExportService {
     @Autowired
     private VideoMapper videoMapper;
 
-    @Autowired
-    private ServiceProperties serviceProperties;
-
-    private static final int ASSET_PROCESSING_LIMIT = 100;
-    private static final int PLAYLIST_PROCESSING_LIMIT = 10;
-
-    public void export() {
-        exportAssets();
-        exportPlaylists();
-    }
-
-    private void exportAssets() {
-        List<Long> ids = assetSyncRepository.queryIdsForExport();
-        if (ids.isEmpty()) {
-            log.info("There are no video changes to export");
-            return;
-        }
-        List<List<Long>> partitions = Lists.partition(ids, ASSET_PROCESSING_LIMIT);
-        partitions.forEach(currentIds -> {
-            List<AssetSync> result = assetSyncRepository.findAllByIdInOrderByCreated(currentIds);
-            if (serviceProperties.isTargetVideoInsertEnabled()) {
-                result.forEach(this::processAssetSync);
-            } else {
-                result.forEach(this::processAssetSyncWithoutInsert);
-            }
-        });
-    }
+    private static final String MC_VOD_SYNC = "mc-vod-sync";
 
     @Transactional
-    public void processAssetSyncWithoutInsert(AssetSync assetSync) {
+    public void processAssetSyncWithoutInsert(AssetSync assetSync, CompositeSummary summary) {
         try {
             if (SyncType.DELETE.equals(assetSync.getSyncType())) {
                 //delete not necessary, remove only from all playlists
                 assetSync.setExportedSuccess(Date.from(Instant.now()));
+                summary.getVideo().incDelete();
             } else {
-                Asset asset = assetRepository.findById(assetSync.getCatalogId()).orElseThrow(EntityNotFoundException::new);
+                Asset asset = assetRepository.findById(assetSync.getAssetId()).orElseThrow(EntityNotFoundException::new);
                 Video assetVideo = videoMapper.toVideo(asset);
                 String videoId = asset.getReferenceId();
                 if (StringUtils.isBlank(videoId)) {
                     Video video = bcClient.getVideoByReferenceId(asset.getCatalogId());
-                    videoId = video.getId();
-                    asset.setReferenceId(videoId);
-                    assetRepository.save(asset);
+                    if (Objects.isNull(video)) {
+                        summary.getVideo().incSkip();
+                    } else {
+                        videoId = video.getId();
+                        asset.setReferenceId(videoId);
+                        assetRepository.save(asset);
+                    }
+                }
+                if (StringUtils.isNotBlank(videoId)) {
+                    assetVideo.addTagsItem(MC_VOD_SYNC);
+                    bcClient.updateVideo(videoId, assetVideo);
+                    summary.getVideo().incUpdate();
                 }
-                bcClient.updateVideo(videoId, assetVideo);
                 assetSync.setExportedSuccess(Date.from(Instant.now()));
             }
+            summary.getVideo().incSuccess();
         } catch (Exception e) {
             log.error(e);
             assetSync.setExportedError(Date.from(Instant.now()));
+            summary.getVideo().incError();
         } finally {
             assetSyncRepository.save(assetSync);
         }
     }
 
     @Transactional
-    public void processAssetSync(AssetSync assetSync) {
+    public void processAssetSync(AssetSync assetSync, CompositeSummary summary) {
         try {
             if (SyncType.DELETE.equals(assetSync.getSyncType())) {
                 //delete not necessary, remove only from all playlists
                 assetSync.setExportedSuccess(Date.from(Instant.now()));
+                summary.getVideo().incDelete();
             } else {
-                Asset asset = assetRepository.findById(assetSync.getCatalogId()).orElseThrow(EntityNotFoundException::new);
+                Asset asset = assetRepository.findById(assetSync.getAssetId()).orElseThrow(EntityNotFoundException::new);
+                //TODO handle deleted
+
                 Video assetVideo = videoMapper.toVideo(asset);
-                assetVideo.setTags(Collections.singletonList("mc-vod-sync"));
+                assetVideo.addTagsItem(MC_VOD_SYNC);
+
                 if (SyncType.INSERT.equals(assetSync.getSyncType())) {
-                    Video createdVideo = bcClient.createVideo(assetVideo);
-                    asset.setReferenceId(createdVideo.getId());
+                    Video existingAssetVideo = null;
+                    if (StringUtils.isBlank(asset.getReferenceId())) {
+                        existingAssetVideo = bcClient.getVideoByReferenceId(asset.getCatalogId());
+                    }
+
+                    if (Objects.isNull(existingAssetVideo)) {
+                        Video createdVideo = bcClient.createVideo(assetVideo);
+                        asset.setReferenceId(createdVideo.getId());
+                        summary.getVideo().incInsert();
+                    } else {
+                        summary.getVideo().incUpdate();
+                        asset.setReferenceId(existingAssetVideo.getId());
+                    }
                     assetRepository.save(asset);
                 }
                 if (SyncType.UPDATE.equals(assetSync.getSyncType())) {
                     if (StringUtils.isBlank(asset.getReferenceId())) {
                         throw new IllegalArgumentException("Can not update Video when Asset entity reference ID is empty");
                     }
-                    bcClient.updateVideo(asset.getReferenceId(), assetVideo);
+
+                    Video origVideo = bcClient.getVideoById(asset.getReferenceId());
+                    origVideo.setName(assetVideo.getName());
+                    bcClient.updateVideo(asset.getReferenceId(), origVideo);
+                    summary.getVideo().incUpdate();
                 }
                 assetSync.setExportedSuccess(Date.from(Instant.now()));
+                summary.getVideo().incSuccess();
             }
         } catch (Exception e) {
             log.error(e);
             assetSync.setExportedError(Date.from(Instant.now()));
+            summary.getVideo().incError();
         } finally {
             assetSyncRepository.save(assetSync);
         }
     }
 
-    private void exportPlaylists() {
-        List<Long> ids = playlistSyncRepository.queryIdsForExport();
-        if (ids.isEmpty()) {
-            log.info("There are no playlist changes to export");
-            return;
-        }
-        List<List<Long>> partitions = Lists.partition(ids, PLAYLIST_PROCESSING_LIMIT);
-        partitions.forEach(currentIds -> {
-            List<PlaylistSync> result = playlistSyncRepository.findAllByIdInOrderByCreated(currentIds);
-            if (serviceProperties.isTargetPlaylistInsertEnabled()) {
-                result.forEach(this::processPlaylistSync);
-            } else {
-                result.forEach(this::processPlaylistSyncWithoutInsert);
-            }
-        });
-    }
-
-
     @Transactional
-    public void processPlaylistSync(PlaylistSync playlistSync) {
+    public void processPlaylistSync(PlaylistSync playlistSync, CompositeSummary summary) {
         try {
             if (SyncType.DELETE.equals(playlistSync.getSyncType())) {
                 playlistSync.setExportedSuccess(Date.from(Instant.now()));
+                summary.getPlaylist().incDelete();
             } else {
-                Playlist playlist = bcClient.getPlaylistsByName(playlistSync.getName());
+                Playlist playlist = bcClient.getPlaylistsById(playlistSync.getName());
                 //TODO check if all Asset has rferenceId
                 if (Objects.nonNull(playlist)) {
                     playlist.setVideoIds(toApiIds(playlistSync.getIds()));
                     bcClient.updatePlaylist(playlist);
+                    summary.getPlaylist().incUpdate();
                 } else {
                     playlist = new Playlist();
                     playlist.setName(playlistSync.getName());
-                    playlist.setDescription("mc-vod-sync");
+                    playlist.setDescription(MC_VOD_SYNC);
                     playlist.setVideoIds(toApiIds(playlistSync.getIds()));
                     bcClient.createPlaylist(playlist);
+                    summary.getPlaylist().incInsert();
                 }
                 playlistSync.setExportedSuccess(Date.from(Instant.now()));
             }
+            summary.getPlaylist().incSuccess();
         } catch (Exception e) {
             log.error(e);
             playlistSync.setExportedError(Date.from(Instant.now()));
+            summary.getPlaylist().incError();
         } finally {
             playlistSyncRepository.save(playlistSync);
         }
     }
 
-    private List<String> toApiIds(List<String> ids) {
-        return ids.stream().map(assetRepository::findReferenceIdByCatalogId).collect(Collectors.toList());
-    }
-
     @Transactional
-    public void processPlaylistSyncWithoutInsert(PlaylistSync playlistSync) {
+    public void processPlaylistSyncWithoutInsert(PlaylistSync playlistSync, CompositeSummary summary) {
         try {
             if (SyncType.DELETE.equals(playlistSync.getSyncType())) {
                 playlistSync.setExportedSuccess(Date.from(Instant.now()));
+                summary.getPlaylist().incDelete();
             } else {
-                Playlist playlist = bcClient.getPlaylistsByName(playlistSync.getName());
+                Playlist playlist = bcClient.getPlaylistsById(playlistSync.getName());
                 if (Objects.nonNull(playlist)) {
                     playlist.setVideoIds(toApiIds(playlistSync.getIds()));
                     bcClient.updatePlaylist(playlist);
+                    summary.getPlaylist().incUpdate();
                 } else {
                     log.warn("Playlist not found: {}", playlistSync.getName());
+                    summary.getPlaylist().incSkip();
                 }
                 playlistSync.setExportedSuccess(Date.from(Instant.now()));
             }
+            summary.getPlaylist().incSuccess();
         } catch (Exception e) {
             log.error(e);
             playlistSync.setExportedError(Date.from(Instant.now()));
+            summary.getPlaylist().incError();
+        } finally {
+            playlistSyncRepository.save(playlistSync);
         }
     }
+
+    private List<String> toApiIds(List<Long> ids) {
+        return ids.stream().map(assetRepository::findReferenceIdById).collect(Collectors.toList());
+    }
 }
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/SyncProcessor.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/out/SyncProcessor.java
new file mode 100644 (file)
index 0000000..0906b88
--- /dev/null
@@ -0,0 +1,83 @@
+package hu.user.mcvodsync.service.out;
+
+
+import com.google.common.collect.Lists;
+import hu.user.mcvodsync.db.AssetSync;
+import hu.user.mcvodsync.db.PlaylistSync;
+import hu.user.mcvodsync.db.repository.AssetSyncRepository;
+import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
+import hu.user.mcvodsync.service.ServiceProperties;
+import hu.user.mcvodsync.service.data.CompositeSummary;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.time.Instant;
+import java.util.List;
+
+@Log4j2
+@Component
+public class SyncProcessor {
+
+    @Autowired
+    private AssetSyncRepository assetSyncRepository;
+
+    @Autowired
+    private PlaylistSyncRepository playlistSyncRepository;
+
+    @Autowired
+    private ServiceProperties serviceProperties;
+
+    @Autowired
+    private SyncExportService syncExportService;
+
+    private static final int ASSET_PROCESSING_LIMIT = 100;
+    private static final int PLAYLIST_PROCESSING_LIMIT = 10;
+
+
+    public CompositeSummary export() {
+        CompositeSummary summary = CompositeSummary.builder().started(Instant.now()).build();
+        exportAssets(summary);
+        exportPlaylists(summary);
+        summary.setFinished(Instant.now());
+        log.info(summary);
+        return summary;
+    }
+
+    private void exportAssets(CompositeSummary summary) {
+        List<Long> ids = assetSyncRepository.queryIdsForExport();
+        if (ids.isEmpty()) {
+            log.info("There are no video changes to export");
+            return;
+        }
+        List<List<Long>> partitions = Lists.partition(ids, ASSET_PROCESSING_LIMIT);
+        partitions.forEach(currentIds -> {
+            summary.getVideo().incAll();
+            List<AssetSync> result = assetSyncRepository.findAllByIdInOrderByCreated(currentIds);
+            if (serviceProperties.isTargetVideoInsertEnabled()) {
+                result.forEach(sync -> syncExportService.processAssetSync(sync, summary));
+            } else {
+                result.forEach(sync -> syncExportService.processAssetSyncWithoutInsert(sync, summary));
+            }
+        });
+    }
+
+    private void exportPlaylists(CompositeSummary summary) {
+        List<Long> ids = playlistSyncRepository.queryIdsForExport();
+        if (ids.isEmpty()) {
+            log.info("There are no playlist changes to export");
+            return;
+        }
+        List<List<Long>> partitions = Lists.partition(ids, PLAYLIST_PROCESSING_LIMIT);
+        partitions.forEach(currentIds -> {
+            summary.getPlaylist().incAll();
+            List<PlaylistSync> result = playlistSyncRepository.findAllByIdInOrderByCreated(currentIds);
+            if (serviceProperties.isTargetPlaylistInsertEnabled()) {
+                result.forEach(sync -> syncExportService.processPlaylistSync(sync, summary));
+            } else {
+                result.forEach(sync -> syncExportService.processPlaylistSyncWithoutInsert(sync, summary));
+            }
+        });
+    }
+
+}
index b257702f14d3b6c6fb00cfdc4a35505feb2ea173..d79721cb6c952e79db2ecb0f54ff56e8d39580c1 100644 (file)
@@ -2,6 +2,7 @@ package hu.user.mcvodsync.service.out;
 
 import com.brightcove.cms.client.model.Video;
 import hu.user.mcvodsync.db.Asset;
+import org.apache.commons.lang3.StringUtils;
 import org.mapstruct.Mapper;
 import org.mapstruct.ReportingPolicy;
 
@@ -9,13 +10,12 @@ import java.util.*;
 
 @Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
 public interface VideoMapper {
-
-    String NOTES = "notes";
-    String SHOW = "show";
-    String SEASON = "season";
-    String EPISODE = "episode";
-    String RATING_TV = "rating_tv";
-    String PRODUCTION_YEAR = "production_year";
+    String CUSTOM_NOTES = "notes";
+    String CUSTOM_SHOW = "show";
+    String CUSTOM_SEASON = "season";
+    String CUSTOM_EPISODE = "episode";
+    String CUSTOM_RATING_TV = "rating_tv";
+    String CUSTOM_PRODUCTION_YEAR = "production_year";
     String ACTORS_TALENT = "actors_talent";
     String DIRECTOR = "director";
     String GENRE = "genre";
@@ -38,20 +38,40 @@ public interface VideoMapper {
         Video result = new Video();
         result.setReferenceId(asset.getCatalogId());
         result.setName(asset.getProgLocalTitle());
-        result.putCustomFieldsItem(NOTES, asset.getHubInfo());
-        result.putCustomFieldsItem(SHOW, asset.getSeasonLocalTitle());
+        result.setLongDescription(asset.getProgSynopsisFullHun());
+        result.setDescription(asset.getProgSynopsisShortHun());
+        result.putCustomFieldsItem(CUSTOM_NOTES, asset.getHubInfo());
+        result.putCustomFieldsItem(CUSTOM_SHOW, asset.getSeasonLocalTitle());
         if (Objects.nonNull(asset.getSeasonNr())) {
-            result.putCustomFieldsItem(SEASON, asset.getSeasonNr().toString());
+            result.putCustomFieldsItem(CUSTOM_SEASON, asset.getSeasonNr().toString());
         }
         if (Objects.nonNull(asset.getEpisodeNr())) {
-            result.putCustomFieldsItem(EPISODE, asset.getEpisodeNr().toString());
+            result.putCustomFieldsItem(CUSTOM_EPISODE, asset.getEpisodeNr().toString());
         }
-        if (Objects.nonNull(asset.getAgeRating())
+        if (StringUtils.isNotBlank(asset.getAgeRating())
                 && valid_AgeRating.contains(asset.getAgeRating())) {
-            result.putCustomFieldsItem(RATING_TV, asset.getAgeRating());
+            result.putCustomFieldsItem(CUSTOM_RATING_TV, asset.getAgeRating());
         }
         if (Objects.nonNull(asset.getProductionYear())) {
-            result.putCustomFieldsItem(PRODUCTION_YEAR, asset.getProductionYear().toString());
+            result.putCustomFieldsItem(CUSTOM_PRODUCTION_YEAR, asset.getProductionYear().toString());
+        }
+        if (StringUtils.isNotBlank(asset.getDirector())) {
+            result.putCustomFieldsItem(DIRECTOR, asset.getDirector());
+        }
+        if (StringUtils.isNotBlank(asset.getDirector())) {
+            result.putCustomFieldsItem(DIRECTOR, asset.getDirector());
+        }
+        if (StringUtils.isNotBlank(asset.getXCast())) {
+            result.putCustomFieldsItem(ACTORS_TALENT, asset.getXCast());
+        }
+        if (StringUtils.isNotBlank(asset.getProgGenre1())) {
+            result.addTagsItem(asset.getProgGenre1());
+        }
+        if (StringUtils.isNotBlank(asset.getProgGenre2())) {
+            result.addTagsItem(asset.getProgGenre2());
+        }
+        if (StringUtils.isNotBlank(asset.getProgGenre3())) {
+            result.addTagsItem(asset.getProgGenre3());
         }
         return result;
     }
@@ -61,15 +81,20 @@ public interface VideoMapper {
                 .referenceId(video.getId())
                 .catalogId(video.getReferenceId())
                 .progLocalTitle(video.getName())
+                .progSynopsisFullHun(video.getLongDescription())
+                .progSynopsisShortHun(video.getDescription())
                 .build();
         Optional<Map<String, String>> opCustomFields = Optional.ofNullable(video.getCustomFields());
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(NOTES))).ifPresent(result::setHubInfo);
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(SHOW))).ifPresent(result::setSeasonLocalTitle);
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(SEASON))).ifPresent(val -> result.setSeasonNr(Integer.parseInt(val)));
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(EPISODE))).ifPresent(val -> result.setEpisodeNr(Integer.parseInt(val)));
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(RATING_TV))).ifPresent(result::setAgeRating);
-        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(PRODUCTION_YEAR))).ifPresent(val -> result.setProductionYear(Integer.parseInt(val)));
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_NOTES))).ifPresent(result::setHubInfo);
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_SHOW))).ifPresent(result::setSeasonLocalTitle);
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_SEASON))).ifPresent(val -> result.setSeasonNr(Integer.parseInt(val)));
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_EPISODE))).ifPresent(val -> result.setEpisodeNr(Integer.parseInt(val)));
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_RATING_TV))).ifPresent(result::setAgeRating);
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(CUSTOM_PRODUCTION_YEAR))).ifPresent(val -> result.setProductionYear(Integer.parseInt(val)));
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(DIRECTOR))).ifPresent(result::setDirector);
+        opCustomFields.flatMap(fields -> Optional.ofNullable(fields.get(ACTORS_TALENT))).ifPresent(result::setXCast);
         return result;
     }
 
+
 }
index b97f81d1e8eb54036b4b128aa01d6c507e733b1f..8893abe1755b4ee6a3a2f402b11f4aab298d2ffb 100644 (file)
@@ -1,7 +1,9 @@
 package hu.user.mcvodsync.service.schedule;
 
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import hu.user.mcvodsync.service.event.ExportCompletedEvent;
-import hu.user.mcvodsync.service.out.AssetExportService;
+import hu.user.mcvodsync.service.event.ExportStartedEvent;
+import hu.user.mcvodsync.service.out.SyncProcessor;
 import lombok.SneakyThrows;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,21 +15,23 @@ import org.springframework.stereotype.Component;
 public class ScheduledExport implements Runnable {
     @Autowired
     private ApplicationEventPublisher applicationEventPublisher;
-    
+
     @Autowired
-    private AssetExportService assetExportService;
+    private SyncProcessor syncProcessor;
 
     @SneakyThrows
     @Override
     public void run() {
+        CompositeSummary summary = null;
         try {
+            applicationEventPublisher.publishEvent(new ExportStartedEvent(this));
             log.info("ScheduledExport started");
-            assetExportService.export();
+            summary = syncProcessor.export();
         } catch (Exception e) {
             log.error("ScheduledExport error!", e);
         } finally {
-            applicationEventPublisher.publishEvent(new ExportCompletedEvent(null, this));
-            log.info("ScheduledImport finished");
+            applicationEventPublisher.publishEvent(new ExportCompletedEvent(this, summary));
+            log.info("ScheduledExport finished");
         }
     }
 
index f268bffe183f0c5006ee547fe687da94f4421a5c..bba8f9e6ead6f53dad93c399019b6df13a3fcfd3 100644 (file)
@@ -2,9 +2,9 @@ package hu.user.mcvodsync.service.schedule;
 
 import hu.user.mcvodsync.db.UploadFile;
 import hu.user.mcvodsync.db.repository.UploadFileRepository;
+import hu.user.mcvodsync.service.data.CompositeSummary;
 import hu.user.mcvodsync.service.event.ImportCompletedEvent;
 import hu.user.mcvodsync.service.event.ImportStartedEvent;
-import hu.user.mcvodsync.service.in.ImportSummary;
 import hu.user.mcvodsync.service.in.VodXlsProcessor;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,12 +27,12 @@ public class ScheduledImport implements Runnable {
 
     @Override
     public void run() {
-        ImportSummary summary = null;
+        CompositeSummary summary = null;
         try {
             Optional<UploadFile> opUploadFile = uploadFileRepository.findFirstByOrderByCreatedDesc();
             if (opUploadFile.isPresent()) {
-                log.info("ScheduledImport started from {}", opUploadFile.get().getName());
                 applicationEventPublisher.publishEvent(new ImportStartedEvent(this, opUploadFile.get().getName()));
+                log.info("ScheduledImport started from {}", opUploadFile.get().getName());
                 summary = vodXlsProcessor.process(opUploadFile.get().getName(), opUploadFile.get().getFile());
             }
         } catch (Exception e) {
similarity index 91%
rename from mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledSunriseChacker.java
rename to mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/schedule/ScheduledSunsetChacker.java
index 0ecb68c02f29e65277e6d6412e98f9a3ce7805f4..7b394dfbc7fb8b4fd1dadfd53a418b5df579e9c9 100644 (file)
@@ -9,7 +9,7 @@ import java.util.concurrent.ThreadLocalRandom;
 @Log4j2
 @Component
 //@ConditionalOnExpression("'${mc-vod-sync.scheduler.sunrise-checker}'=='true'")
-public class ScheduledSunriseChacker implements Runnable {
+public class ScheduledSunsetChacker implements Runnable {
 
     @SneakyThrows
     @Override
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/time/TimeUtils.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/time/TimeUtils.java
new file mode 100644 (file)
index 0000000..dbde844
--- /dev/null
@@ -0,0 +1,14 @@
+package hu.user.mcvodsync.service.time;
+
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class TimeUtils {
+    private static final Format format = new SimpleDateFormat("yyyy.MM.dd. HH:mm:ss");
+
+    public static String toString(long timestamp) {
+        Date date = new Date(timestamp);
+        return format.format(date);
+    }
+}
index 386241814c598f931ea1f155b2dc6e81472693dc..344e45d27ac7a86fe83439ef70560d6dff8a5479 100644 (file)
@@ -12,4 +12,5 @@ import org.springframework.stereotype.Component;
 public class ApplicationProperties {
     String userName;
     String password;
+    boolean admin;
 }
index eb603f7b107b07157d30cfddec3c64c05da2f717..ffb151a1d02ad536ab15dcafafe0802b9d61d383 100644 (file)
@@ -2,9 +2,8 @@ package hu.user.mcvodsync.ui;
 
 public class Constants {
     public static final String APPLICATION_NAME = "MC-VOD-SYNC";
-    public static final String NAV_IMPORT_FILE = "/import-file";
+    public static final String NAV_MAIN = "/main";
     public static final String NAV_BROWSE_REMOTE = "/browse-remote";
-    public static final String NAV_EXPORT_DATA = "/export-data";
     public static final String NAV_ASSOCIATES = "/associates";
     public static final String NAV_LOGIN = "/login";
     public static final String NAV_LOGOUT = "/logout";
index 3ec17f7b6241dbdf37007c23237b7803ee2b1e9a..cba8c67f363f0a8b37b2b3c387f548e7a79285af 100644 (file)
@@ -16,7 +16,7 @@ public class ResourceConfigurer {
         return "login";
     }
 
-    @GetMapping({Constants.NAV_IMPORT_FILE, Constants.NAV_BROWSE_REMOTE, Constants.NAV_EXPORT_DATA, Constants.NAV_ASSOCIATES})
+    @GetMapping({Constants.NAV_MAIN, Constants.NAV_BROWSE_REMOTE, Constants.NAV_ASSOCIATES})
     public String index() {
         return "index";
     }
index e35cc79be8a5da94a10c6d387829ef1b34c8598f..c07ff7fef263f1a42488f56f3be759fb21a64aa4 100644 (file)
@@ -41,7 +41,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .anyRequest().authenticated()
                 .and()
                 .formLogin()
-                .loginPage(Constants.NAV_LOGIN).defaultSuccessUrl(Constants.NAV_IMPORT_FILE)
+                .loginPage(Constants.NAV_LOGIN).defaultSuccessUrl(Constants.NAV_MAIN)
                 .and()
                 .logout().logoutUrl(Constants.NAV_LOGOUT).logoutSuccessUrl(Constants.NAV_LOGIN)
                 .and()
index 6b9ad0df6377013eddcf54a11c236b1fd5ff2f16..29c786d442daf13410468ecf73ae4c68998404d1 100644 (file)
@@ -16,17 +16,19 @@ import java.util.List;
 @Log4j2
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 public class BrightCovePlaylistDataModel extends CachedSpringDataModel<Playlist> {
+
     @Autowired
     private BrightCoveClient brightCoveClient;
 
     @Override
     public List<Playlist> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
-        return brightCoveClient.getPlaylists(page * pageSize, pageSize, "description:mc-vod-sync");
+        //"description:mc-vod-sync"
+        return brightCoveClient.getPlaylists(page * pageSize, pageSize, null);
     }
 
     @Override
     public int getResultSetCount() {
-        return brightCoveClient.getPlaylistCount("description:mc-vod-sync");
+        return brightCoveClient.getPlaylistCount(null);
     }
 
     public void refresh() {
index 959cb5a34291df8ded909117b1341ba4bf55dffb..b094b8dd30fd78b7e7a5e93723856e4017300c6c 100644 (file)
@@ -12,9 +12,14 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Component;
 import org.zkoss.zul.FieldComparator;
+import org.zkoss.zul.Messagebox;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 @Component
 @Log4j2
@@ -30,16 +35,50 @@ public class BrightCoveVideoDataModel extends CachedSpringDataModel<Video> {
             return null;
         }
         List<List<String>> partitions = Lists.partition(playlist.getVideoIds(), pageSize);
-        String query = StringUtils.join(partitions.get(page), ",");
-        return brightCoveClient.getVideos(pageSize * page, pageSize, query);
+        List<String> currentIds = partitions.get(page);
+        String query = StringUtils.join(currentIds, ",");
+        List<Video> unsortedList = null;
+        try {
+            unsortedList = brightCoveClient.getVideos(pageSize * page, pageSize, query);
+        } catch (Exception e) {
+            Messagebox.show(e.getMessage());
+            ArrayList<Video> videos = new ArrayList<>();
+            for (int i = 0; i < playlist.getVideoIds().size(); i++) {
+                Video video = new Video();
+                video.setName("Error!");
+                videos.add(video);
+            }
+            return videos;
+        }
+        return sortVideos(page, unsortedList, currentIds);
+    }
+
+    private static List<Video> sortVideos(int page, List<Video> unsortedList, List<String> currentIds) {
+        List<Video> result = new ArrayList<>(unsortedList.size());
+        Map<String, Video> mappedVideos;
+        try {
+            mappedVideos = unsortedList.stream().collect(Collectors.toMap(Video::getId, Function.identity()));
+            currentIds.forEach(id -> result.add(mappedVideos.get(id)));
+        } catch (Exception e) {
+            log.error(e);
+        }
+        return result;
     }
 
     @Override
     public int getResultSetCount() {
-        if (Objects.isNull(playlist) || Objects.isNull(playlist.getVideoIds())) {
+        if (Objects.isNull(playlist)) {
             return 0;
         }
-        return playlist.getVideoIds().size();
+
+        List<String> videoIds = null;
+        try {
+            videoIds = playlist.getVideoIds();
+        } catch (Exception e) {
+            log.error(e);
+        }
+
+        return Objects.isNull(videoIds) ? 0 : videoIds.size();
     }
 
     public void refresh(Playlist playlist) {
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ExportDataViewModel.java b/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ExportDataViewModel.java
deleted file mode 100644 (file)
index 1048516..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-package hu.user.mcvodsync.ui.view;
-
-import hu.user.mcvodsync.service.config.ScheduledTasks;
-import hu.user.mcvodsync.service.event.ExportCompletedEvent;
-import hu.user.mcvodsync.ui.Constants;
-import lombok.Getter;
-import lombok.extern.log4j.Log4j2;
-import org.springframework.context.ApplicationListener;
-import org.zkoss.bind.annotation.Command;
-import org.zkoss.bind.annotation.Init;
-import org.zkoss.zk.ui.select.annotation.VariableResolver;
-import org.zkoss.zk.ui.select.annotation.WireVariable;
-import org.zkoss.zk.ui.util.Clients;
-import org.zkoss.zkplus.spring.DelegatingVariableResolver;
-
-@Getter
-@Log4j2
-@VariableResolver(DelegatingVariableResolver.class)
-public class ExportDataViewModel implements ApplicationListener<ExportCompletedEvent> {
-
-    @WireVariable
-    private ScheduledTasks scheduledTasks;
-
-    @Init
-    public void init() {
-        Clients.evalJavaScript(String.format("pushNav('%s')", Constants.NAV_EXPORT_DATA));
-        onRefresh();
-    }
-
-    @Command
-    public void onRefresh() {
-        log.info("Refresh");
-    }
-
-    @Command
-    public void onStartExport() {
-        log.info("Starting export");
-        scheduledTasks.startExport();
-    }
-
-    @Override
-    public void onApplicationEvent(ExportCompletedEvent event) {
-        log.info("Export completed");
-    }
-}
index debc4c0c98c2af0aee99137934909fa0afe24d20..3ae301a3aa0b867fb81cf28c2ffd3f9ab4bb3b26 100644 (file)
@@ -24,14 +24,12 @@ public class ImportEventHandler {
     @Async
     @EventListener
     public void handleEvent(ImportStartedEvent evt) {
-        log.info("ImportStartedEvent handle");
         Optional.ofNullable(startedConsumer).ifPresent(c -> c.accept(evt));
     }
 
     @Async
     @EventListener
     public void handleEvent(ImportCompletedEvent evt) {
-        log.info("ImportCompletedEvent handle");
         Optional.ofNullable(completedConsumer).ifPresent(c -> c.accept(evt));
     }
 }
index 27df65f801299a9cb67b333aaf52e59255b3ccec..c4b4a747bdd4a057682a0645699fda45399b709a 100644 (file)
@@ -9,6 +9,7 @@ import hu.user.mcvodsync.db.repository.AssetSyncRepository;
 import hu.user.mcvodsync.db.repository.PlaylistSyncRepository;
 import hu.user.mcvodsync.db.repository.UploadFileRepository;
 import hu.user.mcvodsync.service.config.ScheduledTasks;
+import hu.user.mcvodsync.ui.ApplicationProperties;
 import hu.user.mcvodsync.ui.Constants;
 import hu.user.mcvodsync.ui.auth.CurrentProfile;
 import hu.user.mcvodsync.ui.session.SessionSettings;
@@ -31,6 +32,9 @@ import org.zkoss.zul.Messagebox;
 @Setter
 public class IndexViewModel {
 
+    @WireVariable
+    private ApplicationProperties applicationProperties;
+
     @WireVariable
     private BuildProperties buildProperties;
 
@@ -71,12 +75,13 @@ public class IndexViewModel {
     @Command
     public void onTimer() {
         BindUtils.postNotifyChange(scheduledTasks, "status");
+        BindUtils.postNotifyChange(scheduledTasks, "outOfSync");
     }
 
     @Command
     public void route(String path) {
         if (Constants.NAV_ROOT.equals(path))
-            path = Constants.NAV_IMPORT_FILE;
+            path = Constants.NAV_MAIN;
         setPage("~." + path + ".zul");
         BindUtils.postNotifyChange(this, "page");
     }
@@ -89,18 +94,24 @@ public class IndexViewModel {
     }
 
     @Command
-    public void onReset() {
-        cleanupLocal();
+    public void onResetRemote() {
         cleanupRemote();
         Messagebox.show("Cleanup completed.", "Info", Messagebox.OK, Messagebox.INFORMATION);
     }
 
+    @Command
+    public void onResetLocal() {
+        cleanupLocal();
+        Messagebox.show("Cleanup completed.", "Info", Messagebox.OK, Messagebox.INFORMATION);
+    }
+
     private void cleanupLocal() {
         log.info("cleanupLocal");
         playlistSyncRepository.deleteAllInBatch();
         assetSyncRepository.deleteAllInBatch();
         assetRepository.deleteAllInBatch();
         uploadFileRepository.deleteAllInBatch();
+        scheduledTasks.reset();
         log.info("cleanupLocal OK");
     }
 
@@ -108,6 +119,7 @@ public class IndexViewModel {
         log.info("cleanupRemote");
         cleanupRemotePlaylists();
         cleanupRemoteVideos();
+        scheduledTasks.reset();
         log.info("cleanupRemote OK");
     }
 
similarity index 91%
rename from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportFileViewModel.java
rename to mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/MainViewModel.java
index 394e312b4e9fe0c8dc9fcf22af0d420c30e19919..5cf385d5b7170f537c9f7ead632007a6278923ad 100644 (file)
@@ -27,7 +27,7 @@ import static hu.user.mcvodsync.ui.data.common.CachedDataModel.NATURAL;
 
 @Getter
 @Log4j2
-public class ImportFileViewModel extends FilterActiveViewModel<UploadFile> {
+public class MainViewModel extends FilterActiveViewModel<UploadFile> {
 
     @WireVariable
     ImportFileDataModel importFileDataModel;
@@ -45,7 +45,7 @@ public class ImportFileViewModel extends FilterActiveViewModel<UploadFile> {
 
     @Override
     protected String getNavigation() {
-        return Constants.NAV_IMPORT_FILE;
+        return Constants.NAV_MAIN;
     }
 
     @Init
@@ -61,6 +61,7 @@ public class ImportFileViewModel extends FilterActiveViewModel<UploadFile> {
 
     @Command
     public void onTimer() {
+        BindUtils.postNotifyChange(scheduledTasks, "exportSummary");
         BindUtils.postNotifyChange(scheduledTasks, "importSummary");
     }
 
@@ -88,4 +89,10 @@ public class ImportFileViewModel extends FilterActiveViewModel<UploadFile> {
         scheduledTasks.startImport();
     }
 
+    @Command
+    public void onStartExport() {
+        scheduledTasks.startExport();
+    }
+
+
 }
index 09683498ab8e8daeddf64251f993eb578ff051c0..4a764ee0d21c7dab7408f2a7ceaf1b802d7e534c 100644 (file)
@@ -2,7 +2,7 @@
 <zk>
     <config-name/>
     <session-config>
-        <session-timeout>300</session-timeout>
+        <session-timeout>3600</session-timeout>
         <timeout-uri>/timeout</timeout-uri>
     </session-config>
     <client-config>
         <name>org.zkoss.zul.nativebar</name>
         <value>true</value>
     </library-property>
-    <language-addon>
-        <component>
-            <component-name>menuitem</component-name>
-            <extends>menuitem</extends>
-            <property>
-                <property-name>autodisable</property-name>
-                <property-value>self</property-value>
-            </property>
-        </component>
-    </language-addon>
     <!--    PROD    -->
     <!--    <desktop-config>-->
     <!--        <file-check-period>600</file-check-period>&lt;!&ndash; unit: seconds &ndash;&gt;-->
index b83435c9bf1950616195ed7cc5b46f9000942ef6..b23780ce77d7a1a5c623eb7690780648e1fc4a15 100644 (file)
@@ -6,24 +6,30 @@
     <!--        font-weight: bold;-->
     <!--        }-->
     <!--    </style>-->
-    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.AssociatesViewModel')">
-        <caption label="Munkatársak"/>
+    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.AssociatesViewModel')"
+            style="margin: 20px 0 20px 0">
         <borderlayout>
             <north flex="true">
-                <toolbar>
-                    <toolbarbutton label="Hozzáadás" iconSclass="z-icon-plus" onClick="@command('onAdd')"/>
-                    <toolbarbutton label="Szerkesztés" iconSclass="z-icon-edit" onClick="@command('onEdit')"
-                                   disabled="@load(empty vm.selectedEntity)"/>
-                    <toolbarbutton label="Törlés" iconSclass="z-icon-remove" onClick="@command('onDelete')"
-                                   disabled="@load(empty vm.selectedEntity)"/>
-                    <separator orient="vertical"/>
-                    <toolbarbutton mode="toggle" iconSclass="z-icon-check" label="Aktív"
-                                   checked="@bind(vm.filterShowActive)"/>
-                    <toolbarbutton mode="toggle" iconSclass="z-icon-ban" label="Inaktív"
-                                   checked="@bind(vm.filterShowInActive)"/>
-                    <toolbarbutton mode="toggle" iconSclass="z-icon-adjust" label="Mind"
-                                   checked="@bind(vm.filterShowBoth)"/>
-                </toolbar>
+                <vlayout>
+                    <hbox pack="start" align="center" hflex="true" vflex="true" style="padding: 10px">
+                        <label style="font-size: 1.5em; font-weight:bold; color: gray" value="USERS"/>
+                    </hbox>
+                    <toolbar>
+                        <toolbarbutton label="Add" iconSclass="z-icon-plus" onClick="@command('onAdd')"
+                                       style="font-size: 1.2em"/>
+                        <toolbarbutton label="Edit" iconSclass="z-icon-edit" onClick="@command('onEdit')"
+                                       disabled="@load(empty vm.selectedEntity)" style="font-size: 1.2em"/>
+                        <!--                        <toolbarbutton label="Delete" iconSclass="z-icon-remove" onClick="@command('onDelete')"-->
+                        <!--                                       disabled="@load(empty vm.selectedEntity)" style="font-size: 1.2em"/>-->
+                        <space bar="true"/>
+                        <toolbarbutton mode="toggle" iconSclass="z-icon-check" label="Active"
+                                       checked="@bind(vm.filterShowActive)" style="font-size: 1.2em"/>
+                        <toolbarbutton mode="toggle" iconSclass="z-icon-ban" label="Inactive"
+                                       checked="@bind(vm.filterShowInActive)" style="font-size: 1.2em"/>
+                        <toolbarbutton mode="toggle" iconSclass="z-icon-adjust" label="All"
+                                       checked="@bind(vm.filterShowBoth)" style="font-size: 1.2em"/>
+                    </toolbar>
+                </vlayout>
             </north>
             <center border="none" flex="true">
                 <listbox vflex="true" model="@load(vm.associatesDataModel)"
index c6d332ad11afdc701489195495a60bbed8f2f3eb..1e6a19c0ffc9a8ec89b97b627c19f4ce83a6e374 100644 (file)
@@ -1,42 +1,71 @@
 <zk>
-    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.BrowseRemoteViewModel')">
-        <caption label="Browse BrightCove"/>
+    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.BrowseRemoteViewModel')"
+            style="margin: 20px 0 20px 0">
         <borderlayout>
             <north hflex="true">
-                <toolbar>
-                    <toolbarbutton label="Reload" iconSclass="z-icon-retweet" onClick="@command('onRefresh')"/>
-                </toolbar>
+                <vlayout>
+                    <hbox pack="start" align="center" hflex="true" vflex="true" style="padding: 10px">
+                        <label style="font-size: 1.5em; font-weight:bold; color: gray" value="BROWSE BRIGHTCOVE"/>
+                    </hbox>
+                    <toolbar>
+                        <toolbarbutton label="Reload" iconSclass="z-icon-refresh" onClick="@command('onRefresh')"
+                                       style="font-size: 1.2em"/>
+                    </toolbar>
+                </vlayout>
             </north>
             <center border="none" hflex="true" vflex="true">
 
                 <hbox spacing="0" hflex="true" vflex="true">
                     <listbox hflex="true" vflex="true" model="@load(vm.brightCovePlaylistDataModel)"
                              autopaging="true" mold="paging" pagingPosition="top" multiple="false"
-                             selectedItem="@bind(vm.selectedPlaylist)">
+                             selectedItem="@bind(vm.selectedPlaylist)" sizedByContent="true" span="true">
                         <listhead sizable="true">
                             <listheader label="ID" align="left"/>
                             <listheader label="Name" align="left"/>
                             <listheader label="Video count" align="left"/>
+                            <listheader label="Description" align="left"/>
                         </listhead>
                         <template name="model">
                             <listitem>
                                 <listcell label="@load(each.id)"/>
                                 <listcell label="@load(each.name)"/>
                                 <listcell label="@load(each.getVideoIds().size())"/>
+                                <listcell label="@load(each.description)"/>
                             </listitem>
                         </template>
                     </listbox>
                     <splitter collapse="before"/>
                     <listbox hflex="true" vflex="true" model="@load(vm.brightCoveVideoDataModel)"
-                             autopaging="true" mold="paging" pagingPosition="top" multiple="false">
+                             autopaging="true" mold="paging" pagingPosition="top" multiple="false"
+                             sizedByContent="true" span="true">
                         <listhead sizable="true">
                             <listheader label="ID" align="left"/>
-                            <listheader label="Catalog ID" align="left"/>
+                            <listheader label="Reference ID" align="left"/>
+                            <listheader label="Notes" align="left"/>
+                            <listheader label="Name" align="left"/>
+                            <listheader label="Description" align="left"/>
+                            <listheader label="Show" align="left"/>
+                            <listheader label="Season" align="left"/>
+                            <listheader label="Episode" align="left"/>
+                            <listheader label="Production year" align="left"/>
+                            <listheader label="Rating TV" align="left"/>
+                            <listheader label="Tags" align="left"/>
+                            <listheader label="Long description" align="left"/>
                         </listhead>
                         <template name="model">
                             <listitem>
                                 <listcell label="@load(each.id)"/>
                                 <listcell label="@load(each.referenceId)"/>
+                                <listcell label="@load(each.customFields['notes'])"/>
+                                <listcell label="@load(each.name)"/>
+                                <listcell label="@load(each.description)"/>
+                                <listcell label="@load(each.customFields['show'])"/>
+                                <listcell label="@load(each.customFields['season'])"/>
+                                <listcell label="@load(each.customFields['episode'])"/>
+                                <listcell label="@load(each.customFields['production_year'])"/>
+                                <listcell label="@load(each.customFields['rating_tv'])"/>
+                                <listcell label="@load(each.tags)"/>
+                                <listcell label="@load(each.longDescription)"/>
                             </listitem>
                         </template>
                     </listbox>
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/export-stats.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/export-stats.zul
new file mode 100644 (file)
index 0000000..2dda262
--- /dev/null
@@ -0,0 +1,181 @@
+<zk>
+    <style>
+        .bold-font {
+        font-weight: bold;
+        font-size: 1.3em;
+        }
+    </style>
+    <vlayout>
+        <grid span="true">
+            <columns>
+                <column hflex="min"/>
+                <column hflex="1"/>
+                <column hflex="1"/>
+                <column hflex="1"/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="left" valign="bottom">
+                        <label value="Started:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.startedFormatted)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Finished:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.finishedFormatted)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <label value="Video statistics:"/>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="All:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.all)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Success:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.success)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Error:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.error)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Skipped:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.skip)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="Inserted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.insert)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Updated:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.update)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Deleted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.video.delete)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <label value="Playlist statistics:"/>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="All:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.all)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Success:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.success)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Error:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.error)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Skipped:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.skip)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="Inserted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.insert)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Updated:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.update)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Deleted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.exportSummary.playlist.delete)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+
+    </vlayout>
+</zk>
\ No newline at end of file
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/import-stats.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/import-stats.zul
new file mode 100644 (file)
index 0000000..7727e5b
--- /dev/null
@@ -0,0 +1,180 @@
+<zk>
+    <style>
+        .bold-font {
+        font-weight: bold;
+        font-size: 1.3em;
+        }
+    </style>
+    <vlayout>
+        <grid span="true">
+            <columns>
+                <column hflex="min"/>
+                <column hflex="1"/>
+                <column hflex="1"/>
+                <column hflex="1"/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="left" valign="bottom">
+                        <label value="Started:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.startedFormatted)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Finished:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.finishedFormatted)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <label value="Video statistics:"/>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="All:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.all)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Success:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.success)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Error:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.error)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Skipped:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.skip)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="Inserted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.insert)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Updated:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.update)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Deleted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.video.delete)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <label value="Playlist statistics:"/>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="All:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.all)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Success:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.success)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Error:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.error)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Skipped:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.skip)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+        <grid span="true">
+            <columns>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+                <column/>
+            </columns>
+            <rows>
+                <row>
+                    <cell align="right" valign="bottom">
+                        <label value="Inserted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.insert)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Updated:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.update)"/>
+                    </cell>
+                    <cell align="right" valign="bottom">
+                        <label value="Deleted:"/>
+                    </cell>
+                    <cell align="left" valign="middle">
+                        <label sclass="bold-font" value="@load(vm.scheduledTasks.importSummary.playlist.delete)"/>
+                    </cell>
+                </row>
+            </rows>
+        </grid>
+    </vlayout>
+</zk>
\ No newline at end of file
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/test.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/form/test.zul
new file mode 100644 (file)
index 0000000..1c2e272
--- /dev/null
@@ -0,0 +1,3 @@
+<zk>
+    <label value="ANYÁD"/>
+</zk>
\ No newline at end of file
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/import-file.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/import-file.zul
deleted file mode 100644 (file)
index 1b962a6..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<zk>
-    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.ImportFileViewModel')">
-        <timer delay="2000" onTimer="@command('onTimer')" repeats="true"/>
-        <caption label="Import file"/>
-        <borderlayout>
-            <north hflex="true">
-                <toolbar>
-                    <toolbarbutton label="Upload" iconSclass="z-icon-plus" upload="true"
-                                   onUpload="@command('onUploadFile')"/>
-                    <!--                    <toolbarbutton label="Törlés" iconSclass="z-icon-remove" onClick="@command('onDelete')"-->
-                    <!--                                   disabled="@load(empty vm.selectedEntity)"/>-->
-                </toolbar>
-            </north>
-            <center border="none" hflex="true" vflex="true">
-
-                <hbox spacing="0" hflex="true" vflex="true">
-                    <listbox id="partnersList" hflex="2" vflex="true" model="@load(vm.importFileDataModel)"
-                             autopaging="true" mold="paging" pagingPosition="top" multiple="false"
-                             onSelect="@command('onListSelection')" onDoubleClick="@command('onEdit')">
-                        <listhead sizable="true">
-                            <listheader label="Created" sort="auto(created)" align="left"
-                                        sortDirection="@load(vm.cols['created'].sortDirection)"/>
-                            <listheader label="Name" sort="auto(name)" align="left"
-                                        sortDirection="@load(vm.cols['name'].sortDirection)"/>
-                            <listheader label="Size" sort="auto(size)" align="left"
-                                        sortDirection="@load(vm.cols['size'].sortDirection)"/>
-                        </listhead>
-                        <template name="model">
-                            <listitem>
-                                <listcell label="@load(each.created)"/>
-                                <listcell label="@load(each.name)"/>
-                                <listcell label="@load(each.size)"/>
-                            </listitem>
-                        </template>
-                    </listbox>
-                    <splitter collapse="before"/>
-                    <window title="Last import statistics" hflex="true" vflex="true">
-                        <vlayout>
-                            <grid span="true">
-                                <columns>
-                                    <column hflex="min"/>
-                                    <column hflex="1"/>
-                                    <column hflex="min"/>
-                                    <column hflex="1"/>
-                                </columns>
-                                <rows>
-                                    <row>
-                                        <cell align="left" valign="bottom">
-                                            <label value="Started:"/>
-                                        </cell>
-                                        <cell align="center" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.started)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                        <cell align="left" valign="bottom">
-                                            <label value="Finished:"/>
-                                        </cell>
-                                        <cell align="center" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.finished)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                    </row>
-                                </rows>
-                            </grid>
-                            <grid span="true">
-                                <columns>
-                                    <column/>
-                                    <column/>
-                                    <column/>
-                                    <column/>
-                                    <column/>
-                                    <column/>
-                                </columns>
-                                <rows>
-                                    <row>
-                                        <cell align="right" valign="bottom">
-                                            <label value="All:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.all)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                        <cell align="right" valign="bottom">
-                                            <label value="Success:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.success)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                        <cell align="right" valign="bottom">
-                                            <label value="Error:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.error)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                    </row>
-                                    <row>
-                                        <cell align="right" valign="bottom">
-                                            <label value="Inserted:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.inserted)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                        <cell align="right" valign="bottom">
-                                            <label value="Updated:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.updated)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                        <cell align="right" valign="bottom">
-                                            <label value="Deleted:"/>
-                                        </cell>
-                                        <cell align="left" valign="middle">
-                                            <label value="@load(vm.scheduledTasks.importSummary.deleted)"
-                                                   sclass="hightlight"/>
-                                        </cell>
-                                    </row>
-                                </rows>
-                            </grid>
-
-                        </vlayout>
-                    </window>
-                </hbox>
-
-            </center>
-        </borderlayout>
-    </window>
-</zk>
\ No newline at end of file
index b863493f8e7ba1eb227c84c2bc9c00dfa186b451..da9f5e8703c4196e02c145901a5cd8a2bcc1df83 100644 (file)
@@ -26,7 +26,7 @@
         }
     </script>
     <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.IndexViewModel')">
-        <timer delay="2000" onTimer="@command('onTimer')" repeats="true"/>
+        <timer delay="1000" onTimer="@command('onTimer')" repeats="true"/>
         <caption sclass="header" id="appHeader">
             <div style="display: block">
                 <div style="display: inline; float: left">
                 <vlayout>
                     <hlayout valign="middle">
                         <menubar autodrop="true" hflex="true">
-                            <menuitem iconSclass="z-icon-cloud-download" label="Import file"
-                                      onClick="@command(vm.route(Constants.NAV_IMPORT_FILE))"/>
-                            <menuitem iconSclass="z-icon-cloud-upload" label="Export data"
-                                      onClick="@command(vm.route(Constants.NAV_EXPORT_DATA))"/>
+                            <menuitem iconSclass="z-icon-retweet" label="Synchronization"
+                                      onClick="@command(vm.route(Constants.NAV_MAIN))"/>
                             <menuitem image="~./static/images/bc.ico" label="Browse BrightCove"
                                       onClick="@command(vm.route(Constants.NAV_BROWSE_REMOTE))"/>
-                            <menuseparator/>
+                            <menuseparator visible="@load(vm.applicationProperties.admin)"/>
                             <menuitem iconSclass="z-icon-user" label="Users"
-                                      onClick="@command(vm.route(Constants.NAV_ASSOCIATES))"/>
-                            <menuitem iconSclass="z-icon-trash" label="Reset data"
-                                      onClick="@command('onReset')"/>
+                                      onClick="@command(vm.route(Constants.NAV_ASSOCIATES))"
+                                      visible="@load(vm.applicationProperties.admin)"/>
+                            <menuitem iconSclass="z-icon-trash" label="Reset local data"
+                                      onClick="@command('onResetLocal')"
+                                      visible="@load(vm.applicationProperties.admin)"/>
+                            <menuitem iconSclass="z-icon-trash" label="Reset remote data"
+                                      onClick="@command('onResetRemote')"
+                                      visible="@load(vm.applicationProperties.admin)"/>
                         </menubar>
                         <hbox hflex="min" pack="right">
                         </hbox>
             <center border="none" hflex="true">
                 <include src="@load(vm.page)" hflex="true" vflex="true"/>
             </center>
-            <south height="50px">
-                <hbox pack="end" align="center" hflex="true" vflex="true">
-                    <label style="font-size: 1.5em; padding-right: 20px; color: navy"
-                           value="@load(vm.scheduledTasks.status)"/>
-                </hbox>
+            <south>
+                <hlayout>
+                    <hbox pack="start" align="center" hflex="true" vflex="true">
+                        <label style="font-size: 1.5em; font-weight: bold; padding: 20px; color: red"
+                               value="Out of sync!" visible="@load(vm.scheduledTasks.outOfSync)"/>
+                    </hbox>
+                    <hbox pack="end" align="center" hflex="true" vflex="true">
+                        <label style="font-size: 1.5em; padding: 20px; color: navy"
+                               value="@load(vm.scheduledTasks.status)"/>
+                    </hbox>
+                </hlayout>
             </south>
         </borderlayout>
     </window>
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/main.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/main.zul
new file mode 100644 (file)
index 0000000..d458fd9
--- /dev/null
@@ -0,0 +1,62 @@
+<zk>
+    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.MainViewModel')"
+            style="margin: 20px 0 20px 0">
+        <timer delay="1000" onTimer="@command('onTimer')" repeats="true"/>
+        <borderlayout>
+            <north hflex="true">
+                <vlayout>
+                    <hbox pack="start" align="center" hflex="true" vflex="true" style="padding: 10px">
+                        <label style="font-size: 1.5em; font-weight:bold; color: gray" value="SYNCHRONIZATION"/>
+                    </hbox>
+                    <toolbar>
+                        <toolbarbutton label="Import" iconSclass="z-icon-cloud-download" upload="true"
+                                       onUpload="@command('onUploadFile')" style="font-size: 1.2em"/>
+                        <!--                    <space bar="true"/>-->
+                        <separator orient="vertical"/>
+                        <toolbarbutton label="Export" iconSclass="z-icon-cloud-upload"
+                                       onClick="@command('onStartExport')" style="font-size: 1.2em"/>
+                    </toolbar>
+                </vlayout>
+            </north>
+            <center border="none" hflex="true" vflex="true">
+
+                <hbox spacing="0" hflex="true" vflex="true">
+                    <listbox id="partnersList" hflex="2" vflex="true" model="@load(vm.importFileDataModel)"
+                             autopaging="true" mold="paging" pagingPosition="top" multiple="false"
+                             onSelect="@command('onListSelection')" onDoubleClick="@command('onEdit')">
+                        <listhead sizable="true">
+                            <listheader label="Created" sort="auto(created)" align="left"
+                                        sortDirection="@load(vm.cols['created'].sortDirection)"/>
+                            <listheader label="Name" sort="auto(name)" align="left"
+                                        sortDirection="@load(vm.cols['name'].sortDirection)"/>
+                            <listheader label="Size" sort="auto(size)" align="left"
+                                        sortDirection="@load(vm.cols['size'].sortDirection)"/>
+                        </listhead>
+                        <template name="model">
+                            <listitem>
+                                <listcell label="@load(each.created)"/>
+                                <listcell label="@load(each.name)"/>
+                                <listcell label="@load(each.size)"/>
+                            </listitem>
+                        </template>
+                    </listbox>
+                    <splitter/>
+                    <div hflex="true" vflex="true" style="overflow: auto">
+                        <vbox spacing="0" hflex="true" vflex="true">
+                            <window title="Last import" hflex="true" style="margin: 10px" border="normal"
+                                    visible="@load(not empty vm.scheduledTasks.importSummary)">
+                                <include src="~./form/import-stats.zul"/>
+                            </window>
+                            <window title="Last export" hflex="true" style="margin: 10px" border="normal"
+                                    visible="@load(not empty vm.scheduledTasks.exportSummary)">
+                                <include src="~./form/export-stats.zul"/>
+                            </window>
+                        </vbox>
+                    </div>
+
+                </hbox>
+
+            </center>
+        </borderlayout>
+    </window>
+</zk>
\ No newline at end of file