UI extended, scheduled execution built in
authorVásáry Dániel <vasary@elgekko.net>
Tue, 5 Dec 2023 21:27:31 +0000 (22:27 +0100)
committerVásáry Dániel <vasary@elgekko.net>
Tue, 5 Dec 2023 21:27:31 +0000 (22:27 +0100)
40 files changed:
mc-vod-sync/QUESTIONS.md
mc-vod-sync/mc-vod-sync-app/src/main/resources/application-dev.yaml
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/AssetImportExportIT.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/RepositoryIT.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/scripts/003_create_business_tables.sql
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/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-db/src/main/java/hu/user/mcvodsync/db/repository/UploadFileRepository.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/event/ExportCompletedEvent.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportCompletedEvent.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportStartedEvent.java [new file with mode: 0644]
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/out/AssetExportService.java
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-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 [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCoveVideoDataModel.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/ImportFileDataModel.java [moved from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/UploadFileDataModel.java with 96% similarity]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/BrowseRemoteViewModel.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ExportDataViewModel.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportEventHandler.java [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportFileViewModel.java [moved from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/UploadFilesViewModel.java with 69% similarity]
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/resources/metainfo/zk/zk.xml
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/browse-remote.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/export-data.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/import-file.zul [new file with mode: 0644]
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/index.zul
mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/upload-files.zul [deleted file]

index 196c36f87043ac40968fa242c16a641150e43810..d1c780a2849ecc9719c5fc577487755346d82479 100644 (file)
@@ -1,6 +1,33 @@
-* A custom fields API kellhet? Ott be lehet állítani a custom filed-re pl. azt, hogy kötelező e, így amíg nincs értéke
+actors_talent, Actors/Talent, , string, null required: false
+director, Director, , string, null required: false
+episode, Episode, ,
+enum, [1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21, 22, 23, 24, 25, 26, 3, 4, 5, 6, 7, 8, 9] required: false
+genre, Genre, , enum, [Novel, Spektrum saját gyártás, Thriller, action, adnimation, adult, adventure, animals, comedy]
+required: false
+notes, Notes, , string, null required: false
+parent_network, Parent Network, , enum, [AMC+ Hungary (Selekt), Selekt] required: false
+production_year, Production Year, , string, null required: false
+rating_tv, Rating TV, , enum, [18, 18+] required: false
+season, Season, , enum, [1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 3, 4, 5, 6, 7, 8, 9, Special] required: false
+show, Show, , string, null required: false
+tms_episode_id, TMS Episode ID, , string, null required: false
+tms_movie_id, TMS Movie ID, , string, null required: false
+tms_series_id, TMS Series ID, , string, null required: false
+tms_season_id, TMS Season ID, , string, null required: false
+video_category, Video Category, , enum, [Movie, Series] required: false
+video_type, Video Type, , enum, [Full Episode, Full Movie, Sports] required: false
+s3_captions_url, S3 Captions URL, , string, null required: false
+s3_video_url, S3 Video URL, , string, null required: false
+downloadable, Downloadable, , enum, [NO, YES] required: false
+MaxCustomFields: 30
+
+- Az age_rating jelenleg 18,18+. Adjam hozzá az újakat, vagy dobjam el a nem jó értékeket? A többi enumra is ez a
+  kérdés (episode, season)
+- Mit jelent a season Special?
+- A playlist neve nem kötelezően egyedi, de kezelhető egyedinek? Az update miatt érdekes (episode, season)
+- A custom fields API kellhet? Ott be lehet állítani a custom filed-re pl. azt, hogy kötelező e, így amíg nincs értéke
   addig a videó nem aktív. Ennek használata nélkül is létrehozható video?
-*
+
 * A sunset kezelése is kell, tehát jöhet adat későbbi sunset-el?
 * A sunset és sunrise formátuma legyen egyforma (mindegy melyik) minden sorra!
 * Mik a kötelező mezők? Most: playlist, sunset, sunrise, title
index 7a5ee750ae9cbcf118b0334b6c7b8866c870676d..e5fc5a9c40b060b77ee94f2427d7cc6bd9c4bd21 100644 (file)
@@ -34,11 +34,20 @@ spring:
 logging:
   level:
     org.hibernate.engine.jdbc.spi.SqlExceptionHelper: ERROR
+#    org.springframework.web.client.RestTemplate: DEBUG
+#    org.apache.http: DEBUG
+#    httpclient.wire: DEBUG
 mc-vod-sync:
-  scheduler:
-    import: true
-    export: true
-    sunrise-checker: true
+  service:
+    target-video-insert-enabled: true
+    target-playlist-insert-enabled: true
+    scheduler:
+      import-enabled: false
+      export-enabled: false
+      sunrise-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 * ? *
   application:
     user-name: user
     password: password
index 7d50548aec9d96a516cdca8a9c2ab6a4836416f4..050b363e33cc1a668d1680c1c3b2fcee1b675fc0 100644 (file)
@@ -5,13 +5,21 @@
 
 package hu.user.mcvodsync;
 
+import com.brightcove.cms.client.model.Playlist;
+import com.brightcove.cms.client.model.Video;
+import hu.user.mcvodsync.brightcove.BrightCoveClient;
+import hu.user.mcvodsync.brightcove.PagedSearch;
+import hu.user.mcvodsync.db.Asset;
 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.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.VideoMapper;
 import lombok.extern.log4j.Log4j2;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,8 +29,12 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 
 @Log4j2
@@ -39,6 +51,18 @@ public class AssetImportExportBase {
     @Autowired
     private PlaylistSyncRepository playlistSyncRepository;
 
+    @Autowired
+    private AssetImportService assetImportService;
+
+    @Autowired
+    private AssetExportService assetExportService;
+
+    @Autowired
+    private BrightCoveClient brightCoveClient;
+
+    @Autowired
+    private VideoMapper videoMapper;
+
     protected String getPlaylistSyncIds(String name) {
         List<PlaylistSync> playlists = playlistSyncRepository.findAllByName(name);
         assertEquals(1, playlists.size());
@@ -46,17 +70,64 @@ public class AssetImportExportBase {
     }
 
     protected void cleanup() {
-        cleanupSync();
+        cleanupLocal();
+        cleanupRemote();
         assetRepository.deleteAllInBatch();
     }
 
-    protected void cleanupSync() {
+    protected void cleanupRemote() {
+        log.info("cleanupRemote");
+        cleanupRemotePlaylists();
+        cleanupRemoteVideos();
+        log.info("cleanupRemote OK");
+    }
+
+    private void cleanupRemoteVideos() {
+        PagedSearch<Video> page = PagedSearch.<Video>builder()
+                .query("tags:mc-vod-sync")
+                .sort("reference_id")
+                .build();
+        while (brightCoveClient.getVideosPaged(page)) {
+            page.getData().forEach(this::deleteVideo);
+        }
+
+    }
+
+    private void deleteVideo(Video video) {
+        try {
+            brightCoveClient.deleteVideo(video.getId());
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    private void cleanupRemotePlaylists() {
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("description:mc-vod-sync")
+                .sort("name")
+                .build();
+        while (brightCoveClient.getPlaylistsPaged(page)) {
+            page.getData().forEach(this::deletePlayList);
+        }
+    }
+
+    private void deletePlayList(Playlist playlist) {
+        try {
+            brightCoveClient.deletePlaylist(playlist.getId());
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    protected void cleanupLocal() {
+        log.info("cleanupLocal");
         playlistSyncRepository.deleteAllInBatch();
         assetSyncRepository.deleteAllInBatch();
+        log.info("cleanupLocal OK");
     }
 
-    protected ImportSummary process(String xlsFile) {
-        ImportSummary summary = null;
+    protected ImportSummary importFile(String xlsFile) {
+        ImportSummary summary;
         try {
             Path input = Paths.get(xlsFile);
             summary = vodXlsProcessor.process(input.getFileName().toString(), Files.readAllBytes(input));
@@ -67,6 +138,45 @@ public class AssetImportExportBase {
         return summary;
     }
 
+    protected void exportData() {
+        assetExportService.export();
+    }
+
+
+    protected void assertSynchronized() {
+        List<Asset> assets = assetRepository.findAll();
+        assets.forEach(this::assertVideoSynchronized);
+        Map<String, List<String>> playLists = assetImportService.getPlayLists();
+        playLists.forEach(this::assertPlaylistSynchronized);
+    }
+
+    protected void assertVideoSynchronized(Asset asset) {
+        if (Objects.isNull(asset.getReferenceId())) {
+            throw new IllegalStateException(String.format("Asset reference ID is null for %s", asset.getCatalogId()));
+        }
+        Video video = brightCoveClient.getVideoById(asset.getReferenceId());
+        Asset remoteAsset = videoMapper.toAsset(video);
+        assertEquals(asset.getHubInfo(), remoteAsset.getHubInfo());
+        assertEquals(asset.getEpisodeNr(), remoteAsset.getEpisodeNr());
+        assertEquals(asset.getProgLocalTitle(), remoteAsset.getProgLocalTitle());
+        assertEquals(asset.getReferenceId(), remoteAsset.getReferenceId());
+        assertEquals(asset.getCatalogId(), remoteAsset.getCatalogId());
+        assertEquals(asset.getSeasonLocalTitle(), remoteAsset.getSeasonLocalTitle());
+        assertEquals(asset.getProductionYear(), remoteAsset.getProductionYear());
+    }
+
+    protected void assertPlaylistSynchronized(String playlistName, List<String> ids) {
+        Playlist playlist = null;
+        try {
+            playlist = brightCoveClient.getPlaylistsByName(playlistName);
+        } catch (Exception e) {
+        }
+        assertNotNull(playlist);
+        assertNotNull(playlist.getVideoIds());
+        List<String> remoteIds = playlist.getVideoIds().stream().map(assetRepository::findCatalogIdByReferenceId).collect(Collectors.toList());
+        assertEquals(ids, remoteIds);
+    }
+
     protected void checkSummary(ImportSummary summary, long expectedAll, long expectedInsert, long expectedUpdate, long expectedDelete) {
         assertEquals(expectedAll, summary.getAll());
         assertEquals(expectedAll, summary.getSuccess());
@@ -85,5 +195,4 @@ public class AssetImportExportBase {
         assertEquals(expectedAllCount, playlistSyncRepository.count());
     }
 
-
 }
index 2f89a555c8eca68c57e2216bfed9972a07aba229..cda0ee674e9f1212b3b63ab41e712374bb4febef 100644 (file)
@@ -47,21 +47,24 @@ public class AssetImportExportIT extends AssetImportExportBase {
 //        Path xlsFile = Paths.get("src/test/resources/testdata-big.xlsx");
         log.info("initialLoadTest");
         cleanup();
-        ImportSummary summary = process("src/test/resources/testdata.xlsx");
+        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
         checkSummary(summary, 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 = process("src/test/resources/testdata.xlsx");
-        cleanupSync();
-        summary = process("src/test/resources/testdata-change-video.xlsx");
+        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocal();
+        summary = importFile("src/test/resources/testdata-change-video.xlsx");
         checkSummary(summary, 9, 0, 1, 0);
         checkAsset(1, SyncType.UPDATE, 1);
         checkPlaylist(0, null, 0);
@@ -70,9 +73,9 @@ public class AssetImportExportIT extends AssetImportExportBase {
     @Test
     public void deleteVideoTest() {
         log.info("deleteVideoTest");
-        ImportSummary summary = process("src/test/resources/testdata.xlsx");
-        cleanupSync();
-        summary = process("src/test/resources/testdata-delete-video.xlsx");
+        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocal();
+        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);
@@ -83,9 +86,9 @@ public class AssetImportExportIT extends AssetImportExportBase {
     @Test
     public void changePlaylistOrderTest() {
         log.info("changePlaylistOrderTest");
-        ImportSummary summary = process("src/test/resources/testdata.xlsx");
-        cleanupSync();
-        summary = process("src/test/resources/testdata-change-playlist-order.xlsx");
+        ImportSummary summary = importFile("src/test/resources/testdata.xlsx");
+        cleanupLocal();
+        summary = importFile("src/test/resources/testdata-change-playlist-order.xlsx");
         checkSummary(summary, 8, 0, 1, 0);
         checkAsset(1, SyncType.UPDATE, 1);
         checkPlaylist(1, SyncType.UPDATE, 1);
index 3d42a19117d5293b14eee69fa1595066591a716b..1f20e9b13643894ba275aafcbe6ac2a9876d20e2 100644 (file)
@@ -1,7 +1,6 @@
 package hu.user.mcvodsync;
 
-import com.brightcove.cms.client.model.Playlist;
-import com.brightcove.cms.client.model.Video;
+import com.brightcove.cms.client.model.*;
 import com.google.common.collect.ImmutableMap;
 import hu.user.mcvodsync.brightcove.BrightCoveClient;
 import hu.user.mcvodsync.brightcove.PagedSearch;
@@ -21,6 +20,7 @@ import org.springframework.web.client.HttpServerErrorException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertNotNull;
@@ -52,167 +52,165 @@ public class BrightCoveClientIT {
 
     @Test
     public void testCreate5PlayLists() {
-        try {
-            List<String> ids = getVideos();
-
-            for (int i = 1; i < 6; i++) {
-                Playlist playlist = new Playlist();
-                playlist.setName("Playlist 0000" + i);
-                playlist.setVideoIds(ids);
-                playlist.setDescription("mc-vod-sync");
-                Playlist playList = bcClient.createPlaylist(playlist);
-                logPlaylist(playList);
-            }
-
-        } catch (Exception e) {
-            log.error(e);
+        List<String> ids = getVideos();
+
+        for (int i = 1; i < 6; i++) {
+            Playlist playlist = new Playlist();
+            playlist.setName("Playlist 0000");
+            playlist.setVideoIds(ids);
+            playlist.setDescription("mc-vod-sync");
+            Playlist playList = bcClient.createPlaylist(playlist);
+            logPlaylist(playList);
         }
     }
 
     @Test
     public void testDeleteTestPlayLists() {
-        try {
-            PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
-                    .query("description:mc-vod-sync")
-                    .sort("name")
-                    .build();
-            while (bcClient.getPlaylistsPaged(page)) {
-                page.getData().forEach(this::deletePlayList);
-            }
-
-        } catch (Exception e) {
-            log.error(e);
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("description:mc-vod-sync")
+                .sort("name")
+                .build();
+        while (bcClient.getPlaylistsPaged(page)) {
+            page.getData().forEach(this::deletePlayList);
         }
     }
 
     private void deletePlayList(Playlist playlist) {
-        try {
-            logPlaylist(playlist);
-            bcClient.deletePlaylist(playlist.getId());
-        } catch (Exception e) {
-            log.error(e);
-        }
+        logPlaylist(playlist);
+        bcClient.deletePlaylist(playlist.getId());
     }
 
     @Test
     public void updatePlayLists() {
-        try {
 
-            PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
-                    .query("description:mc-vod-sync")
-                    .sort("name")
-                    .build();
-            bcClient.getPlaylistsPaged(page);
-            Playlist playlist = page.getData().get(0);
-            playlist.setVideoIds(getVideos());
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("description:mc-vod-sync")
+                .sort("name")
+                .build();
+        bcClient.getPlaylistsPaged(page);
+        Playlist playlist = page.getData().get(0);
+        playlist.setVideoIds(getVideos());
 
-            List<String> videoIds = playlist.getVideoIds();
-            assertNotNull(videoIds);
-            String id1 = videoIds.get(0);
-            String id2 = videoIds.get(videoIds.size() - 1);
-            videoIds.set(0, id2);
-            videoIds.set(videoIds.size() - 1, id1);
+        List<String> videoIds = playlist.getVideoIds();
+        assertNotNull(videoIds);
+        String id1 = videoIds.get(0);
+        String id2 = videoIds.get(videoIds.size() - 1);
+        videoIds.set(0, id2);
+        videoIds.set(videoIds.size() - 1, id1);
 
 
-            Playlist playList = bcClient.updatePlaylist(playlist);
-            logPlaylist(playList);
+        Playlist playList = bcClient.updatePlaylist(playlist);
+        logPlaylist(playList);
+    }
 
-        } catch (Exception e) {
-            log.error(e);
-        }
+    @Test
+    public void testGetPlayListCount() {
+        log.info(bcClient.getPlaylistCount(null));
+        log.info(bcClient.getPlaylistCount("description:mc-vod-sync"));
+        log.info(bcClient.getPlaylistCount("renegát"));
     }
 
     @Test
     public void testGetPlayLists() {
-        try {
-            PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
-                    .query("description:mc-vod-sync")
-                    .sort("name")
-                    .build();
-            while (bcClient.getPlaylistsPaged(page)) {
-                page.getData().forEach(this::logPlaylist);
-            }
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("description:mc-vod-sync")
+                .sort("name")
+                .build();
 
-        } catch (Exception e) {
-            log.error(e);
+        while (bcClient.getPlaylistsPaged(page)) {
+            page.getData().forEach(this::logPlaylistName);
+        }
+    }
+
+    @Test
+    public void testGetPlayListsByName() {
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("name:Playlist 0000")
+                .sort("name")
+                .build();
+
+        while (bcClient.getPlaylistsPaged(page)) {
+            page.getData().forEach(this::logPlaylist);
         }
+
     }
 
     @Test
     public void testGetVideos() {
-        try {
-            PagedSearch<Video> page = PagedSearch.<Video>builder()
-                    .query("tags:mc-vod-sync")
-                    .sort("reference_id")
-                    .build();
-            while (bcClient.getVideosPaged(page)) {
-                page.getData().forEach(this::logVideo);
-            }
-        } catch (Exception e) {
-            log.error(e);
+        PagedSearch<Video> page = PagedSearch.<Video>builder()
+                .query("tags:mc-vod-sync")
+                .sort("reference_id")
+                .build();
+        while (bcClient.getVideosPaged(page)) {
+            page.getData().forEach(this::logVideo);
         }
     }
 
 
     @Test
     public void testGetVideoById() {
-        try {
-            Video video = bcClient.getVideoById("6328122715112");
-            logVideo(video);
-        } catch (Exception e) {
-            log.error(e);
-        }
+        Video video = bcClient.getVideoById("6328122715112");
+        logVideo(video);
     }
 
     @Test
     public void testGetVideosById() {
-        try {
-            List<Video> videos = bcClient.getVideosById("6328122715112,6339727091112");
-            videos.forEach(this::logVideo);
-        } catch (Exception e) {
-            log.error(e);
-        }
+        List<Video> videos = bcClient.getVideosById("6328122715112,6339727091112");
+        videos.forEach(this::logVideo);
     }
 
 
     @Test
     public void testCreateVideo() {
-        try {
+        Video video = new Video();
+        video.setName("TEST video 00001");
+        video.setReferenceId("MCVODSYNC10001");
+        video.setTags(Collections.singletonList("mc-vod-sync"));
+        video.setCustomFields(ImmutableMap.of("Notes", "notes"));
+        Video createdVideo = bcClient.createVideo(video);
+        logVideo(createdVideo);
+
+        log.info("Search result");
+        List<Video> videos = bcClient.getVideos(0, 10, "tags:mc-vod-sync");
+        videos.forEach(this::logVideo);
+
+    }
+
+    @Test
+    public void testCreate13Videos() {
+        int i = 13;
+        while (i > 0) {
             Video video = new Video();
-            video.setName("TEST video 00001");
-            video.setReferenceId("MCVODSYNC10001");
+            video.setName("TEST video 0000" + i);
+            video.setReferenceId("MCVODSYNC0000" + i);
             video.setTags(Collections.singletonList("mc-vod-sync"));
-            video.setCustomFields(ImmutableMap.of("Notes", "notes"));
             Video createdVideo = bcClient.createVideo(video);
             logVideo(createdVideo);
-
-            log.info("Search result");
-            List<Video> videos = bcClient.getVideos(0, 10, "tags:mc-vod-sync");
-            videos.forEach(this::logVideo);
-
-
-        } catch (Exception e) {
-            log.error(e);
+            i--;
         }
     }
 
     @Test
-    public void testCreate13Videos() {
-        try {
+    public void testCreateVideoWithCustomFields() {
+        Video video = new Video();
+        video.setName("TEST video 0000 custoom attribute");
+        video.setReferenceId("MCVODSYNC00011");
+        video.setTags(Collections.singletonList("mc-vod-sync"));
+        video.putCustomFieldsItem("rating_tv", "19");
+        Video createdVideo = bcClient.createVideo(video);
+        logVideo(createdVideo);
+    }
 
-            int i = 13;
-            while (i > 0) {
-                Video video = new Video();
-                video.setName("TEST video 0000" + i);
-                video.setReferenceId("MCVODSYNC0000" + i);
-                video.setTags(Collections.singletonList("mc-vod-sync"));
-                Video createdVideo = bcClient.createVideo(video);
-                logVideo(createdVideo);
-                i--;
-            }
-        } catch (Exception e) {
-            log.error(e);
+    @Test
+    public void testGetCustomFields() {
+        VideoFields videoFields = bcClient.getVideoCustomFields();
+        if (Objects.nonNull(videoFields.getCustomFields())) {
+            videoFields.getCustomFields().forEach(this::logVideofieldsCustomField);
         }
+//        if (Objects.nonNull(videoFields.getStandardFields())) {
+//            videoFields.getStandardFields().forEach(this::logVideofieldsStandardField);
+//        }
+        log.info("MaxCustomFields: {}", videoFields.getMaxCustomFields());
     }
 
     @Test
@@ -236,25 +234,15 @@ public class BrightCoveClientIT {
 
     @Test
     public void deleteVideos() {
-        try {
-            List<Video> videos = bcClient.getVideos(0, 10, "tags:mc-vod-sync");
-            videos.forEach(video -> {
-                bcClient.deleteVideo(video.getId());
-            });
-
-        } catch (Exception e) {
-            log.error(e);
-        }
+        List<Video> videos = bcClient.getVideos(0, 10, "tags:mc-vod-sync");
+        videos.forEach(video -> {
+            bcClient.deleteVideo(video.getId());
+        });
     }
 
     @Test
     public void testDeleteVideo() {
-        try {
-//            bcClient.deleteVideo("ref:MCVODSYNC00001");
-            bcClient.deleteVideo("6340725850112,6340726442112,6340725849112,6340727220112");
-        } catch (Exception e) {
-            log.error(e);
-        }
+        bcClient.deleteVideo("6340725850112,6340726442112,6340725849112,6340727220112");
     }
 
     private void logVideo(Video video) {
@@ -265,4 +253,16 @@ public class BrightCoveClientIT {
         log.info("{} {} {} {}\r\n{}", playlist.getId(), playlist.getName(), playlist.getType(), playlist.getDescription(), playlist.getVideoIds());
     }
 
+    private void logPlaylistName(Playlist playlist) {
+        log.info("{} {}", playlist.getId(), playlist.getName());
+    }
+
+    private void logVideofieldsCustomField(VideofieldsCustomField field) {
+        log.info("{}, {}, {}, {}, {} required: {}", field.getId(), field.getDisplayName(), field.getDescription(), field.getType(), field.getEnumValues(), field.getRequired());
+    }
+
+    private void logVideofieldsStandardField(VideofieldsStandardField field) {
+        log.info("{},{}, required: {}", field.getId(), field.getDescription(), field.getRequired());
+    }
+
 }
index dfb22a286b05f38adf456d03a5993de21e5624ae..fce3b775b1a41c5a2730fc122f3abf53675549ff 100644 (file)
@@ -5,6 +5,7 @@
 
 package hu.user.mcvodsync;
 
+import com.google.common.collect.Lists;
 import hu.user.mcvodsync.db.AssetSync;
 import hu.user.mcvodsync.db.PlaylistSync;
 import hu.user.mcvodsync.db.SyncType;
@@ -89,8 +90,9 @@ public class RepositoryIT {
 
     @Test
     public void queryForExport() {
+        assetSyncRepository.deleteAllInBatch();
         List<AssetSync> assetSyncs = new ArrayList<>();
-        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < 10; i++) {
             assetSyncs.add(AssetSync.builder()
                     .syncType(SyncType.INSERT)
                     .catalogId("XXX" + i)
@@ -105,17 +107,18 @@ public class RepositoryIT {
                     .build());
         }
         assetSyncRepository.saveAllAndFlush(assetSyncs);
+        List<Long> ids = assetSyncRepository.queryIdsForExport();
+        assertEquals(30, ids.size());
+        int limit = 20;
 
-        while (true) {
-            List<AssetSync> result = assetSyncRepository.findFirst100ByExportedSuccessIsNullOrderByCreated();
-            if (result.isEmpty()) {
-                break;
-            }
+        List<List<Long>> partitions = Lists.partition(ids, limit);
+        partitions.forEach(currentIds -> {
+            List<AssetSync> result = assetSyncRepository.findAllByIdInOrderByCreated(currentIds);
             result.forEach(this::processAssetSync);
-        }
+        });
 
-        List<AssetSync> result = assetSyncRepository.findFirst100ByExportedSuccessIsNullOrderByCreated();
-        assertTrue(result.isEmpty());
+        ids = assetSyncRepository.queryIdsForExport();
+        assertTrue(ids.isEmpty());
         assetSyncRepository.deleteAllInBatch();
     }
 
index 9116f1068fc6c92ba1b4ffeb89c3a08348696903..8d4d4c8dda0f5a9e0568ce5ac6a8f9af83c7a4de 100644 (file)
@@ -1,6 +1,7 @@
 package hu.user.mcvodsync.brightcove;
 
 import com.brightcove.cms.client.ApiClient;
+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.*;
@@ -30,10 +31,13 @@ import java.util.Objects;
 @Service
 public class BrightCoveClient {
     private String authToken;
+    private long tokenExpires;
+
     public static final String BEARER = "Bearer ";
     private final ApiClient apiClient = new ExtendedApiClient();
     private final PlaylistsApi playListApi = new PlaylistsApi();
     private final VideosApi videosApi = new VideosApi();
+    private final CustomFieldsApi customFieldsApi = new CustomFieldsApi();
 
     @Autowired
     private ApiProperties apiProperties;
@@ -41,6 +45,7 @@ public class BrightCoveClient {
     public BrightCoveClient() {
         playListApi.setApiClient(apiClient);
         videosApi.setApiClient(apiClient);
+        customFieldsApi.setApiClient(apiClient);
     }
 
     private String createToken() {
@@ -54,8 +59,9 @@ public class BrightCoveClient {
                     .setClientSecret(apiProperties.getClientSecret())
                     .buildQueryMessage();
 
-            token = client.accessToken(request, OAuthJSONAccessTokenResponse.class).getAccessToken();
-
+            OAuthJSONAccessTokenResponse accessToken = client.accessToken(request, OAuthJSONAccessTokenResponse.class);
+            token = accessToken.getAccessToken();
+            tokenExpires = System.currentTimeMillis() + accessToken.getExpiresIn() * 1000;
         } catch (Exception e) {
             log.error(e.getMessage());
         }
@@ -63,7 +69,7 @@ public class BrightCoveClient {
     }
 
     private String getToken() {
-        if (StringUtils.isBlank(authToken)) {
+        if (StringUtils.isBlank(authToken) || System.currentTimeMillis() > tokenExpires) {
             authToken = BEARER + createToken();
         }
         return authToken;
@@ -87,21 +93,87 @@ public class BrightCoveClient {
         return playListApi.createPlaylist(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), fields);
     }
 
-    public List<Playlist> getPlaylists(int offset, int limit) throws RestClientException {
-        String q = null;
-        String sort = null;
-        return playListApi.getPlaylists(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), limit, offset, q, sort);
+    public List<Playlist> getPlaylists(int offset, int limit, String query) throws RestClientException {
+        String sort = "name";
+        return playListApi.getPlaylists(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), limit, offset, query, sort);
     }
 
     public int getPlaylistCount(String query) {
         int result = 0;
-        PlaylistCount playlistCount = playListApi.getPlaylistCount(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), query);
+        PlaylistCount playlistCount = getPlaylistCountWithHttpInfo(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken(), query).getBody();
         if (Objects.nonNull(playlistCount) && Objects.nonNull(playlistCount.getCount())) {
             result = playlistCount.getCount();
         }
         return result;
     }
 
+    public ResponseEntity<PlaylistCount> getPlaylistCountWithHttpInfo(String accountId, String contentType, String authorization, String query) throws RestClientException {
+        Object postBody = null;
+
+        // verify the required parameter 'accountId' is set
+        if (accountId == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'accountId' when calling getPlaylistCount");
+        }
+
+        // verify the required parameter 'contentType' is set
+        if (contentType == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'contentType' when calling getPlaylistCount");
+        }
+
+        // verify the required parameter 'authorization' is set
+        if (authorization == null) {
+            throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'authorization' when calling getPlaylistCount");
+        }
+
+        // create path and map variables
+        final Map<String, Object> uriVariables = new HashMap<String, Object>();
+        uriVariables.put("account_id", accountId);
+
+        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>();
+
+        queryParams.putAll(apiClient.parameterToMultiValueMap(null, "q", query));
+
+        if (contentType != null)
+            headerParams.add("Content-Type", apiClient.parameterToString(contentType));
+        if (authorization != null)
+            headerParams.add("Authorization", apiClient.parameterToString(authorization));
+
+        final String[] localVarAccepts = {
+                "application/json"
+        };
+        final List<MediaType> localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
+        final String[] contentTypes = {};
+        final MediaType localVarContentType = apiClient.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);
+    }
+
+
+    public Playlist getPlaylistsByName(String name) throws Exception {
+        Playlist result = null;
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query(String.format("name:%s", name))
+                .sort("name")
+                .build();
+        if (getPlaylistsPaged(page) && Objects.nonNull(page.getData())) {
+            if (page.getData().size() > 1) {
+                throw new Exception(String.format("Multiple playlists found for name %s", name));
+            }
+            if (!page.getData().isEmpty()) {
+                result = page.getData().get(0);
+            }
+        }
+        return result;
+    }
+
+
     public boolean getPlaylistsPaged(PagedSearch<Playlist> page) throws RestClientException {
         if (page.getCount() == 0) {
             int count = getPlaylistCount(page.getQuery());
@@ -268,7 +340,12 @@ public class BrightCoveClient {
         return videosApi.getApiClient().invokeAPI("/v1/accounts/{account_id}/videos{video_ids}", HttpMethod.GET, uriVariables, queryParams, postBody, headerParams, cookieParams, formParams, localVarAccept, localVarContentType, authNames, returnType);
     }
 
+
     public void deletePlaylist(String id) {
         playListApi.deletePlaylists(apiProperties.getAccountId(), "/" + id, MediaType.APPLICATION_JSON_VALUE, getToken());
     }
+
+    public VideoFields getVideoCustomFields() {
+        return customFieldsApi.getVideoFields(apiProperties.getAccountId(), MediaType.APPLICATION_JSON_VALUE, getToken());
+    }
 }
index 4299a286c497a7be0410515f8b45d9ea05db309b..ec2ddfdff98a682f7da6927621eb505c4b3fd09c 100644 (file)
@@ -3,7 +3,7 @@
 
 CREATE TABLE upload_file (
     id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
-    created TIMESTAMP,
+    created TIMESTAMP NOT NULL,
     name VARCHAR(255),
     size INTEGER NOT NULL,
     file BLOB,
index 4043e59e8643f3e5ab308aa469cde9c3ce674a6a..fc45d34420f18ade16d660e7c7884c75406367a7 100644 (file)
@@ -1,11 +1,9 @@
 package hu.user.mcvodsync.db;
 
 import lombok.*;
+import org.hibernate.annotations.CreationTimestamp;
 
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
+import javax.persistence.*;
 import java.io.Serializable;
 import java.util.Date;
 
@@ -20,6 +18,8 @@ public class UploadFile implements Serializable {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     Long id;
 
+    @CreationTimestamp
+    @Column(updatable = false)
     Date created;
 
     String name;
index fd44b2b3573bfdac251a4f7eb85d9de6aaf41d7e..37c8e74cf1ff4026864437842d023544db9917d9 100644 (file)
@@ -22,4 +22,10 @@ public interface AssetRepository extends JpaRepository<Asset, String> {
     @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.catalogId FROM Asset a WHERE a.referenceId = :referenceId")
+    String findCatalogIdByReferenceId(String referenceId);
 }
index 4b0346552455e4ed5f51d1397bbc7f4a5ff12199..df29c9f97865eaffcf5cabe0da100e2681272d18 100644 (file)
@@ -1,11 +1,9 @@
 package hu.user.mcvodsync.db.repository;
 
 import hu.user.mcvodsync.db.AssetSync;
-import hu.user.mcvodsync.db.PlaylistSync;
 import hu.user.mcvodsync.db.SyncType;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
 
 import java.util.List;
 
@@ -13,9 +11,9 @@ public interface AssetSyncRepository extends JpaRepository<AssetSync, String> {
 
     long countBySyncType(SyncType syncType);
 
-    Page<AssetSync> findAllByExportedSuccessIsNullOrderByCreated(Pageable page);
+    @Query("SELECT a.id FROM AssetSync a WHERE a.exportedSuccess IS NULL ORDER BY a.created")
+    List<Long> queryIdsForExport();
 
-    List<AssetSync> findFirst100ByExportedSuccessIsNullOrderByCreated();
+    List<AssetSync> findAllByIdInOrderByCreated(List<Long> id);
 
-    List<PlaylistSync> findAllByOrderByCreated();
 }
index bf8cce15f82e728b11db7166b76cd780aac4432f..ff65fb39797b9b973c154c536313f15327c106d9 100644 (file)
@@ -3,6 +3,7 @@ package hu.user.mcvodsync.db.repository;
 import hu.user.mcvodsync.db.PlaylistSync;
 import hu.user.mcvodsync.db.SyncType;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
 
 import java.util.List;
 
@@ -11,4 +12,9 @@ public interface PlaylistSyncRepository extends JpaRepository<PlaylistSync, Long
     long countBySyncType(SyncType syncType);
 
     List<PlaylistSync> findAllByName(String name);
+
+    @Query("SELECT p.id FROM PlaylistSync p WHERE p.exportedSuccess IS NULL ORDER BY p.created")
+    List<Long> queryIdsForExport();
+
+    List<PlaylistSync> findAllByIdInOrderByCreated(List<Long> id);
 }
index 49c1123b11387e5bf4efe41928b5d275a9c41a8b..e1caa38257cb401a47f2cbad43462832ae0f5678 100644 (file)
@@ -3,5 +3,8 @@ package hu.user.mcvodsync.db.repository;
 import hu.user.mcvodsync.db.UploadFile;
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.Optional;
+
 public interface UploadFileRepository extends JpaRepository<UploadFile, Long>, UploadFileRepositorySearch {
+    Optional<UploadFile> findFirstByOrderByCreatedDesc();
 }
index 6a7717e28c185cd039d46ba86677218ff63b04e1..3cd7c29d26ff7ef754274153ab1274a962bc56d2 100644 (file)
@@ -14,4 +14,23 @@ public class ServiceProperties {
     private boolean targetVideoInsertEnabled;
 
     private boolean targetPlaylistInsertEnabled;
+
+    private Scheduler scheduler;
+
+    @Getter
+    @Setter
+    public static final class Scheduler {
+
+        private boolean importEnabled;
+
+        private String importCron;
+
+        private boolean exportEnabled;
+
+        private String exportCron;
+
+        private boolean sunriseCheckerEnabled;
+
+        private String sunriseCheckerCron;
+    }
 }
index 73b761db5cfd581aea58ab69bb8d6ee6ef871a9d..6407ade8e26a868904deace3379c741cc5b991e3 100644 (file)
@@ -1,18 +1,38 @@
 package hu.user.mcvodsync.service.config;
 
+import hu.user.mcvodsync.service.ServiceProperties;
+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.schedule.ScheduledExport;
 import hu.user.mcvodsync.service.schedule.ScheduledImport;
 import hu.user.mcvodsync.service.schedule.ScheduledSunriseChacker;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
 import org.springframework.scheduling.TaskScheduler;
-import org.springframework.scheduling.support.PeriodicTrigger;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.support.CronTrigger;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
-import java.util.concurrent.TimeUnit;
+import java.time.Instant;
 
+@Log4j2
 @Component
 public class ScheduledTasks {
+
+    @Getter
+    private ImportSummary importSummary;
+
+    public ScheduledTasks() {
+        log.info("ScheduledTasks created");
+    }
+
+    @Autowired
+    private ServiceProperties serviceProperties;
+
     @Autowired
     private TaskScheduler taskScheduler;
 
@@ -28,11 +48,40 @@ public class ScheduledTasks {
     @PostConstruct
     public void scheduleTasks() {
         //new CronTrigger("0 0 4 1/1 * ? *")
+        //new PeriodicTrigger(1, TimeUnit.SECONDS)
 //        https://www.baeldung.com/spring-task-scheduler
-        taskScheduler.schedule(scheduledExport, new PeriodicTrigger(1, TimeUnit.SECONDS));
-        taskScheduler.schedule(scheduledImport, new PeriodicTrigger(1, TimeUnit.SECONDS));
-        //taskScheduler.schedule(scheduledSunriseChacker, new PeriodicTrigger(1, TimeUnit.SECONDS));
+        ServiceProperties.Scheduler scheduler = serviceProperties.getScheduler();
+        if (scheduler.isExportEnabled()) {
+            taskScheduler.schedule(scheduledExport, new CronTrigger(scheduler.getImportCron()));
+        }
+        if (scheduler.isImportEnabled()) {
+            taskScheduler.schedule(scheduledImport, new CronTrigger(scheduler.getExportCron()));
+        }
+        if (scheduler.isSunriseCheckerEnabled()) {
+            taskScheduler.schedule(scheduledSunriseChacker, new CronTrigger(scheduler.getSunriseCheckerCron()));
+        }
     }
 
 
+    public void startImport() {
+        taskScheduler.schedule(scheduledImport, Instant.now());
+    }
+
+    public void startExport() {
+        taskScheduler.schedule(scheduledExport, Instant.now());
+    }
+
+    @Async
+    @EventListener
+    public void handleEvent(ImportStartedEvent evt) {
+        log.info("ImportStartedEvent handle");
+        importSummary = null;
+    }
+
+    @Async
+    @EventListener
+    public void handleEvent(ImportCompletedEvent evt) {
+        log.info("ImportCompletedEvent handle");
+        importSummary = evt.getSummary();
+    }
 }
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportCompletedEvent.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ExportCompletedEvent.java
new file mode 100644 (file)
index 0000000..95c7a62
--- /dev/null
@@ -0,0 +1,18 @@
+package hu.user.mcvodsync.service.event;
+
+import hu.user.mcvodsync.service.in.ImportSummary;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@Setter
+public class ExportCompletedEvent extends ApplicationEvent {
+
+    private final ImportSummary summary;
+
+    public ExportCompletedEvent(ImportSummary summary, Object source) {
+        super(source);
+        this.summary = summary;
+    }
+}
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportCompletedEvent.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportCompletedEvent.java
new file mode 100644 (file)
index 0000000..6e1a8f1
--- /dev/null
@@ -0,0 +1,18 @@
+package hu.user.mcvodsync.service.event;
+
+import hu.user.mcvodsync.service.in.ImportSummary;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@Setter
+public class ImportCompletedEvent extends ApplicationEvent {
+
+    private final ImportSummary summary;
+
+    public ImportCompletedEvent(ImportSummary summary, Object source) {
+        super(source);
+        this.summary = summary;
+    }
+}
diff --git a/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportStartedEvent.java b/mc-vod-sync/mc-vod-sync-service/src/main/java/hu/user/mcvodsync/service/event/ImportStartedEvent.java
new file mode 100644 (file)
index 0000000..0c8bc09
--- /dev/null
@@ -0,0 +1,14 @@
+package hu.user.mcvodsync.service.event;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.ApplicationEvent;
+
+@Getter
+@Setter
+public class ImportStartedEvent extends ApplicationEvent {
+
+    public ImportStartedEvent(Object source) {
+        super(source);
+    }
+}
index 423043d73257d86b3b42578d5205c30cd7ac6b56..9e656bf970cbcd4c22be9ace1ff0bcd62640dbc4 100644 (file)
@@ -43,7 +43,7 @@ public class AssetImportService {
         currentPlaylists = getPlayLists();
     }
 
-    private Map<String, List<String>> getPlayLists() {
+    public Map<String, List<String>> getPlayLists() {
         Map<String, List<String>> result = new HashMap<>();
         List<String> playlistNames = assetRepository.queryDistinctPlaylists();
         playlistNames.forEach(playlist -> {
index 686fb8d1730f5da78b7189034b82f7acb58e2bc8..335e1ea15177615ede446f412ee65de9c25a8d59 100644 (file)
@@ -1,7 +1,9 @@
 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;
@@ -19,8 +21,11 @@ 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;
+import java.util.stream.Collectors;
 
 @Log4j2
 @Service
@@ -43,25 +48,29 @@ public class AssetExportService {
     @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() {
-        while (true) {
-            List<AssetSync> result = assetSyncRepository.findFirst100ByExportedSuccessIsNullOrderByCreated();
-            if (result.isEmpty()) {
-                log.info("There are no video changes to export");
-                break;
-            }
-
+        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);
             }
-        }
+        });
     }
 
     @Transactional
@@ -100,6 +109,7 @@ public class AssetExportService {
             } else {
                 Asset asset = assetRepository.findById(assetSync.getCatalogId()).orElseThrow(EntityNotFoundException::new);
                 Video assetVideo = videoMapper.toVideo(asset);
+                assetVideo.setTags(Collections.singletonList("mc-vod-sync"));
                 if (SyncType.INSERT.equals(assetSync.getSyncType())) {
                     Video createdVideo = bcClient.createVideo(assetVideo);
                     asset.setReferenceId(createdVideo.getId());
@@ -122,50 +132,73 @@ public class AssetExportService {
     }
 
     private void exportPlaylists() {
-        while (true) {
-            List<PlaylistSync> result = assetSyncRepository.findAllByOrderByCreated();
-            if (result.isEmpty()) {
-                log.info("There are no playlist changes to export");
-                break;
-            }
-
+        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) {
         try {
             if (SyncType.DELETE.equals(playlistSync.getSyncType())) {
                 playlistSync.setExportedSuccess(Date.from(Instant.now()));
             } else {
-
-//                Playlist playlist = playlistRepository.findById(assetSync.getCatalogId()).orElseThrow(EntityNotFoundException::new);
-//                Video assetVideo = videoMapper.toVideo(asset);
-//                if (SyncType.INSERT.equals(assetSync.getSyncType())) {
-//                    Video createdVideo = bcClient.createVideo(assetVideo);
-//                    asset.setReferenceId(createdVideo.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);
-//                }
-//                assetSync.setExportedSuccess(Date.from(Instant.now()));
+                Playlist playlist = bcClient.getPlaylistsByName(playlistSync.getName());
+                //TODO check if all Asset has rferenceId
+                if (Objects.nonNull(playlist)) {
+                    playlist.setVideoIds(toApiIds(playlistSync.getIds()));
+                    bcClient.updatePlaylist(playlist);
+                } else {
+                    playlist = new Playlist();
+                    playlist.setName(playlistSync.getName());
+                    playlist.setDescription("mc-vod-sync");
+                    playlist.setVideoIds(toApiIds(playlistSync.getIds()));
+                    bcClient.createPlaylist(playlist);
+                }
+                playlistSync.setExportedSuccess(Date.from(Instant.now()));
             }
         } catch (Exception e) {
             log.error(e);
-//            assetSync.setExportedError(Date.from(Instant.now()));
+            playlistSync.setExportedError(Date.from(Instant.now()));
+        } 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) {
+        try {
+            if (SyncType.DELETE.equals(playlistSync.getSyncType())) {
+                playlistSync.setExportedSuccess(Date.from(Instant.now()));
+            } else {
+                Playlist playlist = bcClient.getPlaylistsByName(playlistSync.getName());
+                if (Objects.nonNull(playlist)) {
+                    playlist.setVideoIds(toApiIds(playlistSync.getIds()));
+                    bcClient.updatePlaylist(playlist);
+                } else {
+                    log.warn("Playlist not found: {}", playlistSync.getName());
+                }
+                playlistSync.setExportedSuccess(Date.from(Instant.now()));
+            }
+        } catch (Exception e) {
+            log.error(e);
+            playlistSync.setExportedError(Date.from(Instant.now()));
+        }
     }
 }
index 0efa5e3025af3dfc834149d23d11358560dcfe08..b257702f14d3b6c6fb00cfdc4a35505feb2ea173 100644 (file)
@@ -5,20 +5,35 @@ import hu.user.mcvodsync.db.Asset;
 import org.mapstruct.Mapper;
 import org.mapstruct.ReportingPolicy;
 
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
+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 NOTES = "notes";
+    String SHOW = "show";
+    String SEASON = "season";
+    String EPISODE = "episode";
+    String RATING_TV = "rating_tv";
+    String PRODUCTION_YEAR = "production_year";
+    String ACTORS_TALENT = "actors_talent";
+    String DIRECTOR = "director";
+    String GENRE = "genre";
+    String PARENT_NETWORK = "parent_network";
 
+    List<String> valid_AgeRating = Arrays.asList("18", "18+");
+
+    /*
+    tms_episode_id, TMS Episode ID, , string, null required: false
+    tms_movie_id, TMS Movie ID, , string, null required: false
+    tms_series_id, TMS Series ID, , string, null required: false
+    tms_season_id, TMS Season ID, , string, null required: false
+    video_category, Video Category, , enum, [Movie, Series] required: false
+    video_type, Video Type, , enum, [Full Episode, Full Movie, Sports] required: false
+    s3_captions_url, S3 Captions URL, , string, null required: false
+    s3_video_url, S3 Video URL, , string, null required: false
+    downloadable, Downloadable, , enum, [NO, YES] required: false
+    */
     default Video toVideo(Asset asset) {
         Video result = new Video();
         result.setReferenceId(asset.getCatalogId());
@@ -31,7 +46,10 @@ public interface VideoMapper {
         if (Objects.nonNull(asset.getEpisodeNr())) {
             result.putCustomFieldsItem(EPISODE, asset.getEpisodeNr().toString());
         }
-        result.putCustomFieldsItem(RATING_TV, asset.getAgeRating());
+        if (Objects.nonNull(asset.getAgeRating())
+                && valid_AgeRating.contains(asset.getAgeRating())) {
+            result.putCustomFieldsItem(RATING_TV, asset.getAgeRating());
+        }
         if (Objects.nonNull(asset.getProductionYear())) {
             result.putCustomFieldsItem(PRODUCTION_YEAR, asset.getProductionYear().toString());
         }
index a81ba9d3a56b4d5393104b7b64a825b0fb17f33c..b97f81d1e8eb54036b4b128aa01d6c507e733b1f 100644 (file)
@@ -1,30 +1,34 @@
 package hu.user.mcvodsync.service.schedule;
 
+import hu.user.mcvodsync.service.event.ExportCompletedEvent;
+import hu.user.mcvodsync.service.out.AssetExportService;
 import lombok.SneakyThrows;
 import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Component;
 
-import java.util.concurrent.ThreadLocalRandom;
-
 @Log4j2
 @Component
-//@ConditionalOnExpression("'${mc-vod-sync.scheduler.export}'=='true'")
 public class ScheduledExport implements Runnable {
-    //    @Scheduled(initialDelay = 2000, fixedDelay = 200)
+    @Autowired
+    private ApplicationEventPublisher applicationEventPublisher;
+    
+    @Autowired
+    private AssetExportService assetExportService;
+
     @SneakyThrows
     @Override
     public void run() {
         try {
-            log.info("Start 1");
-            log.info("Execute 1");
-            int randomNum = ThreadLocalRandom.current().nextInt(100, 2000);
-            Thread.sleep(randomNum);
-            log.info("Finish 1");
-
+            log.info("ScheduledExport started");
+            assetExportService.export();
         } catch (Exception e) {
-            log.error(e);
+            log.error("ScheduledExport error!", e);
+        } finally {
+            applicationEventPublisher.publishEvent(new ExportCompletedEvent(null, this));
+            log.info("ScheduledImport finished");
         }
-
     }
 
 }
index 0f9eaecb5c3f3bfafd84228e096dae79eeca123d..4ad3f22c29fbf2254056ca0322b8f9aeffcbc1e2 100644 (file)
@@ -1,27 +1,45 @@
 package hu.user.mcvodsync.service.schedule;
 
-import lombok.SneakyThrows;
+import hu.user.mcvodsync.db.UploadFile;
+import hu.user.mcvodsync.db.repository.UploadFileRepository;
+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;
+import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Component;
 
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.Optional;
 
 @Log4j2
 @Component
-//@ConditionalOnExpression("'${mc-vod-sync.scheduler.import}'=='true'")
 public class ScheduledImport implements Runnable {
-    @SneakyThrows
+    @Autowired
+    private ApplicationEventPublisher applicationEventPublisher;
+
+    @Autowired
+    private UploadFileRepository uploadFileRepository;
+
+    @Autowired
+    private VodXlsProcessor vodXlsProcessor;
+
     @Override
     public void run() {
+        applicationEventPublisher.publishEvent(new ImportStartedEvent(this));
+        ImportSummary summary = null;
         try {
-            log.info("Start 2");
-            log.info("Execute 2");
-            int randomNum = ThreadLocalRandom.current().nextInt(100, 2000);
-            Thread.sleep(randomNum);
-            log.info("Finish 2");
-
+            log.info("ScheduledImport started");
+            Optional<UploadFile> opUploadFile = uploadFileRepository.findFirstByOrderByCreatedDesc();
+            if (opUploadFile.isPresent()) {
+                summary = vodXlsProcessor.process(opUploadFile.get().getName(), opUploadFile.get().getFile());
+            }
         } catch (Exception e) {
-            log.error(e);
+            log.error("ScheduledImport error!", e);
+        } finally {
+            applicationEventPublisher.publishEvent(new ImportCompletedEvent(summary, this));
+            log.info("ScheduledImport finished");
         }
 
     }
index ea8760bd407f932340c6025a37402126b5cd6dbd..eb603f7b107b07157d30cfddec3c64c05da2f717 100644 (file)
@@ -2,7 +2,9 @@ package hu.user.mcvodsync.ui;
 
 public class Constants {
     public static final String APPLICATION_NAME = "MC-VOD-SYNC";
-    public static final String NAV_UPLOAD_FILES = "/upload-files";
+    public static final String NAV_IMPORT_FILE = "/import-file";
+    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 15b2466106c583479bf77a93856e0ecc0b31273a..3ec17f7b6241dbdf37007c23237b7803ee2b1e9a 100644 (file)
@@ -16,7 +16,7 @@ public class ResourceConfigurer {
         return "login";
     }
 
-    @GetMapping({Constants.NAV_UPLOAD_FILES})
+    @GetMapping({Constants.NAV_IMPORT_FILE, Constants.NAV_BROWSE_REMOTE, Constants.NAV_EXPORT_DATA, Constants.NAV_ASSOCIATES})
     public String index() {
         return "index";
     }
index d67f319c38243adda2fb435d10589925a2769909..e35cc79be8a5da94a10c6d387829ef1b34c8598f 100644 (file)
@@ -41,7 +41,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .anyRequest().authenticated()
                 .and()
                 .formLogin()
-                .loginPage(Constants.NAV_LOGIN).defaultSuccessUrl(Constants.NAV_UPLOAD_FILES)
+                .loginPage(Constants.NAV_LOGIN).defaultSuccessUrl(Constants.NAV_IMPORT_FILE)
                 .and()
                 .logout().logoutUrl(Constants.NAV_LOGOUT).logoutSuccessUrl(Constants.NAV_LOGIN)
                 .and()
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCovePlaylistDataModel.java b/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCovePlaylistDataModel.java
new file mode 100644 (file)
index 0000000..6b9ad0d
--- /dev/null
@@ -0,0 +1,36 @@
+package hu.user.mcvodsync.ui.data;
+
+import com.brightcove.cms.client.model.Playlist;
+import hu.user.mcvodsync.brightcove.BrightCoveClient;
+import hu.user.mcvodsync.ui.data.common.CachedSpringDataModel;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.zkoss.zul.FieldComparator;
+
+import java.util.List;
+
+@Component
+@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");
+    }
+
+    @Override
+    public int getResultSetCount() {
+        return brightCoveClient.getPlaylistCount("description:mc-vod-sync");
+    }
+
+    public void refresh() {
+
+        super.reset();
+    }
+}
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCoveVideoDataModel.java b/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/BrightCoveVideoDataModel.java
new file mode 100644 (file)
index 0000000..959cb5a
--- /dev/null
@@ -0,0 +1,49 @@
+package hu.user.mcvodsync.ui.data;
+
+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.ui.data.common.CachedSpringDataModel;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.zkoss.zul.FieldComparator;
+
+import java.util.List;
+import java.util.Objects;
+
+@Component
+@Log4j2
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class BrightCoveVideoDataModel extends CachedSpringDataModel<Video> {
+    @Autowired
+    private BrightCoveClient brightCoveClient;
+    private Playlist playlist;
+
+    @Override
+    public List<Video> getResultSet(int page, int pageSize, FieldComparator sortComparator) {
+        if (Objects.isNull(playlist) || Objects.isNull(playlist.getVideoIds())) {
+            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);
+    }
+
+    @Override
+    public int getResultSetCount() {
+        if (Objects.isNull(playlist) || Objects.isNull(playlist.getVideoIds())) {
+            return 0;
+        }
+        return playlist.getVideoIds().size();
+    }
+
+    public void refresh(Playlist playlist) {
+        this.playlist = playlist;
+        super.reset();
+    }
+}
similarity index 96%
rename from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/UploadFileDataModel.java
rename to mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/data/ImportFileDataModel.java
index d4b5243c3161c0edab87bd2018ede4c58305cbda..13528ada81762dfbfdf3b698eded6e2422ef4dd4 100644 (file)
@@ -17,7 +17,7 @@ import java.util.List;
 @Component
 @Log4j2
 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
-public class UploadFileDataModel extends CachedSpringDataModel<UploadFile> {
+public class ImportFileDataModel extends CachedSpringDataModel<UploadFile> {
     @Autowired
     UploadFileRepository uploadFileRepository;
 
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/BrowseRemoteViewModel.java b/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/BrowseRemoteViewModel.java
new file mode 100644 (file)
index 0000000..a3dcc10
--- /dev/null
@@ -0,0 +1,46 @@
+package hu.user.mcvodsync.ui.view;
+
+import com.brightcove.cms.client.model.Playlist;
+import hu.user.mcvodsync.ui.Constants;
+import hu.user.mcvodsync.ui.data.BrightCovePlaylistDataModel;
+import hu.user.mcvodsync.ui.data.BrightCoveVideoDataModel;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+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 BrowseRemoteViewModel {
+
+    @WireVariable
+    private BrightCovePlaylistDataModel brightCovePlaylistDataModel;
+
+    @WireVariable
+    private BrightCoveVideoDataModel brightCoveVideoDataModel;
+
+    private Playlist selectedPlaylist;
+
+    @Init
+    public void init() {
+        Clients.evalJavaScript(String.format("pushNav('%s')", Constants.NAV_BROWSE_REMOTE));
+    }
+
+    @Command
+    public void onRefresh() {
+        log.info("Refresh");
+        brightCovePlaylistDataModel.refresh();
+        brightCoveVideoDataModel.refresh(null);
+    }
+
+    public void setSelectedPlaylist(Playlist selectedPlaylist) {
+        this.selectedPlaylist = selectedPlaylist;
+        log.info("Selected {}", selectedPlaylist);
+        brightCoveVideoDataModel.refresh(selectedPlaylist);
+    }
+}
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
new file mode 100644 (file)
index 0000000..1048516
--- /dev/null
@@ -0,0 +1,45 @@
+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");
+    }
+}
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportEventHandler.java b/mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportEventHandler.java
new file mode 100644 (file)
index 0000000..debc4c0
--- /dev/null
@@ -0,0 +1,37 @@
+package hu.user.mcvodsync.ui.view;
+
+import hu.user.mcvodsync.service.event.ImportCompletedEvent;
+import hu.user.mcvodsync.service.event.ImportStartedEvent;
+import lombok.Setter;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+import java.util.function.Consumer;
+
+@Log4j2
+@Component
+public class ImportEventHandler {
+
+    @Setter
+    private Consumer<ImportStartedEvent> startedConsumer;
+
+    @Setter
+    private Consumer<ImportCompletedEvent> completedConsumer;
+
+    @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));
+    }
+}
similarity index 69%
rename from mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/UploadFilesViewModel.java
rename to mc-vod-sync/mc-vod-sync-ui/src/main/java/hu/user/mcvodsync/ui/view/ImportFileViewModel.java
index 62ca38231d68fd8f33688760aab161b35009ffc0..394e312b4e9fe0c8dc9fcf22af0d420c30e19919 100644 (file)
@@ -2,13 +2,15 @@ package hu.user.mcvodsync.ui.view;
 
 import com.google.common.collect.ImmutableMap;
 import hu.user.mcvodsync.db.UploadFile;
+import hu.user.mcvodsync.service.config.ScheduledTasks;
 import hu.user.mcvodsync.ui.Constants;
-import hu.user.mcvodsync.ui.data.UploadFileDataModel;
+import hu.user.mcvodsync.ui.data.ImportFileDataModel;
 import hu.user.mcvodsync.ui.data.common.CachedSpringDataModel;
 import hu.user.mcvodsync.ui.view.common.FilterActiveViewModel;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.zkoss.bind.BindContext;
+import org.zkoss.bind.BindUtils;
 import org.zkoss.bind.annotation.Command;
 import org.zkoss.bind.annotation.ContextParam;
 import org.zkoss.bind.annotation.ContextType;
@@ -25,18 +27,25 @@ import static hu.user.mcvodsync.ui.data.common.CachedDataModel.NATURAL;
 
 @Getter
 @Log4j2
-public class UploadFilesViewModel extends FilterActiveViewModel<UploadFile> {
+public class ImportFileViewModel extends FilterActiveViewModel<UploadFile> {
+
+    @WireVariable
+    ImportFileDataModel importFileDataModel;
+
+    @WireVariable
+    private ScheduledTasks scheduledTasks;
+
     @WireVariable
-    UploadFileDataModel uploadFileDataModel;
+    private ImportEventHandler importEventHandler;
 
     @Override
     protected CachedSpringDataModel<UploadFile> getDataModel() {
-        return uploadFileDataModel;
+        return importFileDataModel;
     }
 
     @Override
     protected String getNavigation() {
-        return Constants.NAV_UPLOAD_FILES;
+        return Constants.NAV_IMPORT_FILE;
     }
 
     @Init
@@ -47,10 +56,16 @@ public class UploadFilesViewModel extends FilterActiveViewModel<UploadFile> {
                 "name", NATURAL,
                 "size", NATURAL
         ));
+
+    }
+
+    @Command
+    public void onTimer() {
+        BindUtils.postNotifyChange(scheduledTasks, "importSummary");
     }
 
     protected void refresh() {
-        uploadFileDataModel.refresh();
+        importFileDataModel.refresh();
     }
 
     @Command
@@ -58,7 +73,7 @@ public class UploadFilesViewModel extends FilterActiveViewModel<UploadFile> {
         UploadEvent evt = (UploadEvent) ctx.getTriggerEvent();
         String lowerCaseFileName = evt.getMedia().getName().toLowerCase();
         if (!lowerCaseFileName.endsWith(".xls") && !lowerCaseFileName.endsWith(".xlsx")) {
-            Messagebox.show("Excel file upload is expected!", "Error", Messagebox.OK, Messagebox.ERROR);
+            Messagebox.show("Excel file is expected!", "Error", Messagebox.OK, Messagebox.ERROR);
             return;
         }
         UploadFile uploadFile = UploadFile.builder()
@@ -68,8 +83,9 @@ public class UploadFilesViewModel extends FilterActiveViewModel<UploadFile> {
                 .created(Date.from(Instant.now()))
                 .build();
 
-        uploadFileDataModel.save(uploadFile);
-        uploadFileDataModel.refresh();
+        importFileDataModel.save(uploadFile);
+        importFileDataModel.refresh();
+        scheduledTasks.startImport();
     }
 
 }
index 4349317ed6e8385413f64904823a2d5036f36287..87b12f358113d969e0d6fed4869bbeee3c2635d0 100644 (file)
@@ -1,5 +1,13 @@
 package hu.user.mcvodsync.ui.view;
 
+import com.brightcove.cms.client.model.Playlist;
+import com.brightcove.cms.client.model.Video;
+import hu.user.mcvodsync.brightcove.BrightCoveClient;
+import hu.user.mcvodsync.brightcove.PagedSearch;
+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.db.repository.UploadFileRepository;
 import hu.user.mcvodsync.ui.Constants;
 import hu.user.mcvodsync.ui.auth.CurrentProfile;
 import hu.user.mcvodsync.ui.session.SessionSettings;
@@ -13,6 +21,7 @@ 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.zul.Messagebox;
 
 
 @Log4j2
@@ -22,15 +31,30 @@ import org.zkoss.zk.ui.select.annotation.WireVariable;
 public class IndexViewModel {
 
     @WireVariable
-    BuildProperties buildProperties;
+    private BuildProperties buildProperties;
 
     @WireVariable
-    SessionSettings sessionSettings;
+    private SessionSettings sessionSettings;
 
     @WireVariable
-    CurrentProfile currentProfile;
+    private CurrentProfile currentProfile;
 
-    String page;
+    @WireVariable
+    private AssetSyncRepository assetSyncRepository;
+
+    @WireVariable
+    private PlaylistSyncRepository playlistSyncRepository;
+
+    @WireVariable
+    private BrightCoveClient brightCoveClient;
+
+    @WireVariable
+    private AssetRepository assetRepository;
+
+    @WireVariable
+    private UploadFileRepository uploadFileRepository;
+
+    private String page;
 
     @Init
     public void init() {
@@ -40,10 +64,12 @@ public class IndexViewModel {
         log.info("Init {}", path);
     }
 
-    private void route(String path) {
+    @Command
+    public void route(String path) {
         if (Constants.NAV_ROOT.equals(path))
-            path = Constants.NAV_UPLOAD_FILES;
+            path = Constants.NAV_IMPORT_FILE;
         setPage("~." + path + ".zul");
+        BindUtils.postNotifyChange(this, "page");
     }
 
 
@@ -53,4 +79,64 @@ public class IndexViewModel {
         BindUtils.postNotifyChange(this, "page");
     }
 
+    @Command
+    public void onReset() {
+        cleanupLocal();
+        cleanupRemote();
+        Messagebox.show("Cleanup completed.", "Info", Messagebox.OK, Messagebox.INFORMATION);
+    }
+
+    private void cleanupLocal() {
+        log.info("cleanupLocal");
+        playlistSyncRepository.deleteAllInBatch();
+        assetSyncRepository.deleteAllInBatch();
+        assetRepository.deleteAllInBatch();
+        uploadFileRepository.deleteAllInBatch();
+        log.info("cleanupLocal OK");
+    }
+
+    protected void cleanupRemote() {
+        log.info("cleanupRemote");
+        cleanupRemotePlaylists();
+        cleanupRemoteVideos();
+        log.info("cleanupRemote OK");
+    }
+
+    private void cleanupRemotePlaylists() {
+        PagedSearch<Playlist> page = PagedSearch.<Playlist>builder()
+                .query("description:mc-vod-sync")
+                .sort("name")
+                .build();
+        while (brightCoveClient.getPlaylistsPaged(page)) {
+            page.getData().forEach(this::deletePlayList);
+        }
+    }
+
+    private void cleanupRemoteVideos() {
+        PagedSearch<Video> page = PagedSearch.<Video>builder()
+                .query("tags:mc-vod-sync")
+                .sort("reference_id")
+                .build();
+        while (brightCoveClient.getVideosPaged(page)) {
+            page.getData().forEach(this::deleteVideo);
+        }
+
+    }
+
+    private void deletePlayList(Playlist playlist) {
+        try {
+            brightCoveClient.deletePlaylist(playlist.getId());
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    private void deleteVideo(Video video) {
+        try {
+            brightCoveClient.deleteVideo(video.getId());
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
 }
index 04e41f19a5a976f22da182027c02e94982bee782..09683498ab8e8daeddf64251f993eb578ff051c0 100644 (file)
         <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;-->
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/browse-remote.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/browse-remote.zul
new file mode 100644 (file)
index 0000000..c6d332a
--- /dev/null
@@ -0,0 +1,48 @@
+<zk>
+    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.BrowseRemoteViewModel')">
+        <caption label="Browse BrightCove"/>
+        <borderlayout>
+            <north hflex="true">
+                <toolbar>
+                    <toolbarbutton label="Reload" iconSclass="z-icon-retweet" onClick="@command('onRefresh')"/>
+                </toolbar>
+            </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)">
+                        <listhead sizable="true">
+                            <listheader label="ID" align="left"/>
+                            <listheader label="Name" align="left"/>
+                            <listheader label="Video count" align="left"/>
+                        </listhead>
+                        <template name="model">
+                            <listitem>
+                                <listcell label="@load(each.id)"/>
+                                <listcell label="@load(each.name)"/>
+                                <listcell label="@load(each.getVideoIds().size())"/>
+                            </listitem>
+                        </template>
+                    </listbox>
+                    <splitter collapse="before"/>
+                    <listbox hflex="true" vflex="true" model="@load(vm.brightCoveVideoDataModel)"
+                             autopaging="true" mold="paging" pagingPosition="top" multiple="false">
+                        <listhead sizable="true">
+                            <listheader label="ID" align="left"/>
+                            <listheader label="Catalog ID" align="left"/>
+                        </listhead>
+                        <template name="model">
+                            <listitem>
+                                <listcell label="@load(each.id)"/>
+                                <listcell label="@load(each.referenceId)"/>
+                            </listitem>
+                        </template>
+                    </listbox>
+                </hbox>
+
+            </center>
+        </borderlayout>
+    </window>
+</zk>
\ No newline at end of file
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/export-data.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/export-data.zul
new file mode 100644 (file)
index 0000000..cd33637
--- /dev/null
@@ -0,0 +1,14 @@
+<zk>
+    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.ExportDataViewModel')">
+        <caption label="Export data"/>
+        <borderlayout>
+            <north hflex="true">
+                <toolbar>
+                    <toolbarbutton label="Synchronize" iconSclass="z-icon-refresh" onClick="@command('onStartExport')"/>
+                </toolbar>
+            </north>
+            <center border="none" flex="true">
+            </center>
+        </borderlayout>
+    </window>
+</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
new file mode 100644 (file)
index 0000000..1b962a6
--- /dev/null
@@ -0,0 +1,131 @@
+<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 d0ceeb112b2878fe09bfbd8f6c8ab577b5e56429..d569f89e5ef1744480665b99b5cb3e72de1fc96f 100644 (file)
@@ -30,7 +30,7 @@
             <div style="display: block">
                 <div style="display: inline; float: left">
                     <hlayout valign="middle">
-                        <image width="24px" height="24px" src="~./static/images/logo.png"/>
+                        <!--                        <image width="24px" height="24px" src="~./static/images/logo.png"/>-->
                         <label value="${Constants.APPLICATION_NAME}"/>
                         <separator orient="vertical"/>
                         <label style="font-size: 0.8em" value="@load(vm.buildProperties.version)"/>
                 <vlayout>
                     <hlayout valign="middle">
                         <menubar autodrop="true" hflex="true">
-                            <menuitem iconSclass="z-icon-group" label="Partnerek"
-                                      onClick="@command(vm.selectPage('~./partners.zul'))"/>
-                            <menuseparator/>
-                            <menuitem iconSclass="z-icon-user" label="Munkatársak"
-                                      onClick="@command(vm.selectPage('~./associates.zul'))"/>
+                            <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 image="~./static/images/bc.ico" label="Browse BrightCove"
+                                      onClick="@command(vm.route(Constants.NAV_BROWSE_REMOTE))"/>
                             <menuseparator/>
+                            <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')"/>
                         </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">
+                <hlayout>
+                    <div width="50px" height="50px" style="background: blue"></div>
+                </hlayout>
+            </south>
         </borderlayout>
     </window>
 </zk>
diff --git a/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/upload-files.zul b/mc-vod-sync/mc-vod-sync-ui/src/main/resources/web/upload-files.zul
deleted file mode 100644 (file)
index d90ecc3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<zk>
-    <window vflex="true" viewModel="@id('vm') @init('hu.user.mcvodsync.ui.view.UploadFilesViewModel')">
-        <caption label="Files"/>
-        <borderlayout>
-            <north flex="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" flex="true">
-                <listbox id="partnersList" vflex="true" model="@load(vm.uploadFileDataModel)"
-                         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>
-            </center>
-        </borderlayout>
-    </window>
-</zk>
\ No newline at end of file