|
1 | 1 | package tech.artcoded.websitev2.pages.memzagram; |
2 | 2 |
|
| 3 | +import lombok.SneakyThrows; |
3 | 4 | import lombok.extern.slf4j.Slf4j; |
4 | 5 | import org.apache.commons.lang3.StringUtils; |
5 | 6 | import org.springframework.cache.annotation.CachePut; |
|
9 | 10 | import org.springframework.stereotype.Service; |
10 | 11 | import org.springframework.web.multipart.MultipartFile; |
11 | 12 | import tech.artcoded.websitev2.notification.NotificationService; |
12 | | -import tech.artcoded.websitev2.rest.util.MockMultipartFile; |
| 13 | +import tech.artcoded.websitev2.upload.FileUpload; |
13 | 14 | import tech.artcoded.websitev2.upload.IFileUploadService; |
14 | 15 | import tech.artcoded.websitev2.upload.ILinkable; |
15 | 16 | import tech.artcoded.websitev2.utils.helper.IdGenerators; |
16 | 17 |
|
17 | | -import java.io.ByteArrayInputStream; |
18 | | -import java.io.ByteArrayOutputStream; |
19 | 18 | import java.util.Collection; |
20 | 19 | import java.util.Date; |
21 | 20 | import java.util.Map; |
22 | 21 | import java.util.Optional; |
| 22 | +import java.util.concurrent.TimeUnit; |
23 | 23 | import java.util.function.Function; |
24 | 24 | import java.util.function.Predicate; |
25 | 25 | import java.util.stream.Collectors; |
26 | 26 |
|
27 | 27 | import static java.lang.Boolean.TRUE; |
28 | 28 | import static java.util.Optional.ofNullable; |
29 | | -import static net.coobird.thumbnailator.Thumbnailator.createThumbnail; |
30 | | -import static tech.artcoded.websitev2.utils.func.CheckedSupplier.toSupplier; |
31 | 29 |
|
32 | 30 | @Service |
33 | 31 | @Slf4j |
34 | 32 | public class MemZaGramService implements ILinkable { |
35 | 33 |
|
36 | | - private final MemZaGramRepository repository; |
37 | | - private final IFileUploadService fileUploadService; |
38 | | - private final NotificationService notificationService; |
39 | | - private static final String MEMZ_ADDED = "MEMZ_ADDED"; |
40 | | - private static final String MEMZ_DELETED = "MEMZ_DELETED"; |
41 | | - |
42 | | - public MemZaGramService(MemZaGramRepository repository, IFileUploadService fileUploadService, |
43 | | - NotificationService notificationService) { |
44 | | - this.repository = repository; |
45 | | - this.fileUploadService = fileUploadService; |
46 | | - this.notificationService = notificationService; |
47 | | - } |
48 | | - |
49 | | - @Async |
50 | | - public void save(String id, String title, String description, Boolean visible, Date dateOfVisibility, |
51 | | - MultipartFile imageUpload) { |
52 | | - MemZaGram memz = ofNullable(id).filter(StringUtils::isNotEmpty).flatMap(this.repository::findById) |
53 | | - .orElseGet(() -> MemZaGram.builder().id(IdGenerators.get()).build()); |
54 | | - |
55 | | - log.info("persisting new image or update visibility..."); |
56 | | - |
57 | | - String imageUploadId = this.uploadAndDeleteIfExist(imageUpload, memz.getId(), memz.getImageUploadId(), visible); |
58 | | - |
59 | | - log.info("generating thumbnail..."); |
60 | | - |
61 | | - String thumbnailUploadId = ofNullable(imageUpload).map(upl -> { |
62 | | - byte[] thumbnailBytes = toSupplier(() -> { |
63 | | - ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
64 | | - createThumbnail(new ByteArrayInputStream(upl.getBytes()), bos, 300, 300); |
65 | | - return bos.toByteArray(); |
66 | | - }).get(); |
67 | | - String fileName = "thumb_".concat(ofNullable(upl.getOriginalFilename()).orElse("")); |
68 | | - return MockMultipartFile.builder().bytes(thumbnailBytes).name(fileName) |
69 | | - .contentType(imageUpload.getContentType()).originalFilename(fileName).build(); |
70 | | - }).map(thumbMultipartFile -> this.uploadAndDeleteIfExist(thumbMultipartFile, memz.getId(), |
71 | | - memz.getThumbnailUploadId(), visible)) |
72 | | - .orElseGet(() -> fileUploadService |
73 | | - .updateVisibility(memz.getThumbnailUploadId(), id, TRUE.equals(visible)).orElse(null)); |
74 | | - |
75 | | - log.info("saving memz to mongo..."); |
76 | | - |
77 | | - MemZaGram save = repository.save(memz.toBuilder().title(title).description(description).updatedDate(new Date()) |
78 | | - .visible(visible).dateOfVisibility(dateOfVisibility).imageUploadId(imageUploadId) |
79 | | - .thumbnailUploadId(thumbnailUploadId).build()); |
80 | | - notificationService.sendEvent("memz %s added or updated".formatted(save.getTitle()), MEMZ_ADDED, save.getId()); |
81 | | - } |
82 | | - |
83 | | - public Page<MemZaGram> findByVisibleIsTrueOrderByCreatedDateDesc(Pageable pageable) { |
84 | | - return repository.findByVisibleIsTrueOrderByCreatedDateDesc(pageable); |
85 | | - } |
86 | | - |
87 | | - public Page<MemZaGram> findAll(Pageable pageable) { |
88 | | - return repository.findAll(pageable); |
89 | | - } |
90 | | - |
91 | | - private String uploadAndDeleteIfExist(MultipartFile file, String id, String uploadId, Boolean visibility) { |
92 | | - String newUploadId; |
93 | | - Optional<String> optionalImageUploadId = ofNullable(file).filter(Predicate.not(MultipartFile::isEmpty)) |
94 | | - .map(upload -> this.fileUploadService.upload(upload, id, TRUE.equals(visibility))); |
95 | | - |
96 | | - if (optionalImageUploadId.isEmpty()) { |
97 | | - newUploadId = ofNullable(uploadId) |
98 | | - .flatMap(uplId -> fileUploadService.updateVisibility(uplId, id, TRUE.equals(visibility))) |
99 | | - .orElseThrow(() -> new RuntimeException("You cannot save without an image!")); |
100 | | - } else { |
101 | | - newUploadId = optionalImageUploadId.get(); |
102 | | - ofNullable(uploadId).ifPresent(fileUploadService::delete); |
103 | | - } |
104 | | - return newUploadId; |
105 | | - } |
106 | | - |
107 | | - @Async |
108 | | - public void delete(String id) { |
109 | | - repository.findById(id).ifPresent(memz -> { |
110 | | - fileUploadService.deleteByCorrelationId(id); |
111 | | - repository.delete(memz); |
112 | | - notificationService.sendEvent("memz %s deleted".formatted(memz.getTitle()), MEMZ_DELETED, memz.getId()); |
113 | | - }); |
114 | | - } |
115 | | - |
116 | | - public void incrementViewsCount(String id) { |
117 | | - repository.findById(id) |
118 | | - .map(memZaGram -> memZaGram.toBuilder().viewsCount(memZaGram.getViewsCount() + 1).build()) |
119 | | - .ifPresent(repository::save); |
120 | | - } |
121 | | - |
122 | | - @Override |
123 | | - @CachePut(cacheNames = "memz_correlation_links", key = "#correlationId") |
124 | | - public String getCorrelationLabel(String correlationId) { |
125 | | - return this.repository.findById(correlationId).map(toLabel()).orElse(null); |
126 | | - } |
127 | | - |
128 | | - private Function<? super MemZaGram, ? extends String> toLabel() { |
129 | | - return mem -> "Memz '%s' ".formatted(mem.getTitle()); |
130 | | - } |
131 | | - |
132 | | - @Override |
133 | | - @CachePut(cacheNames = "memz_all_correlation_links", key = "'allLinks'") |
134 | | - public Map<String, String> getCorrelationLabels(Collection<String> correlationIds) { |
135 | | - return this.repository.findAllById(correlationIds).stream() |
136 | | - .map(f -> Map.entry(f.getId(), this.toLabel().apply(f))) |
137 | | - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); |
138 | | - } |
139 | | - |
140 | | - @Override |
141 | | - public void updateOldId(String correlationId, String oldId, String newId) { |
142 | | - this.repository.findById(correlationId).ifPresent(p -> { |
143 | | - var changed = false; |
144 | | - if (oldId.equals(p.getImageUploadId())) { |
145 | | - p.setImageUploadId(newId); |
146 | | - changed = true; |
147 | | - } |
148 | | - if (oldId.equals(p.getThumbnailUploadId())) { |
149 | | - p.setThumbnailUploadId(newId); |
150 | | - changed = true; |
151 | | - } |
152 | | - if (changed) { |
153 | | - this.repository.save(p.toBuilder().updatedDate(new Date()).build()); |
154 | | - } |
155 | | - }); |
156 | | - |
| 34 | + private final MemZaGramRepository repository; |
| 35 | + private final IFileUploadService fileUploadService; |
| 36 | + private final NotificationService notificationService; |
| 37 | + private static final String MEMZ_ADDED = "MEMZ_ADDED"; |
| 38 | + private static final String MEMZ_DELETED = "MEMZ_DELETED"; |
| 39 | + |
| 40 | + public MemZaGramService(MemZaGramRepository repository, IFileUploadService fileUploadService, |
| 41 | + NotificationService notificationService) { |
| 42 | + this.repository = repository; |
| 43 | + this.fileUploadService = fileUploadService; |
| 44 | + this.notificationService = notificationService; |
| 45 | + } |
| 46 | + |
| 47 | + @Async |
| 48 | + @SneakyThrows |
| 49 | + public void save(String id, String title, String description, Boolean visible, Date dateOfVisibility, |
| 50 | + MultipartFile imageUpload) { |
| 51 | + MemZaGram memz = ofNullable(id).filter(StringUtils::isNotEmpty).flatMap(this.repository::findById) |
| 52 | + .orElseGet(() -> MemZaGram.builder().id(IdGenerators.get()).build()); |
| 53 | + |
| 54 | + log.info("persisting new image or update visibility..."); |
| 55 | + |
| 56 | + String imageUploadId = this.uploadAndDeleteIfExist(imageUpload, memz.getId(), memz.getImageUploadId(), visible); |
| 57 | + |
| 58 | + log.info("getting thumbnail in a few secs..."); |
| 59 | + |
| 60 | + TimeUnit.SECONDS.sleep(60); |
| 61 | + |
| 62 | + String thumbnailUploadId = ofNullable(imageUploadId).flatMap(this.fileUploadService::findOneById) |
| 63 | + .map(FileUpload::getThumbnailId).orElse(null); |
| 64 | + |
| 65 | + log.info("getting {} thumbnail id", thumbnailUploadId); |
| 66 | + log.info("saving memz to mongo..."); |
| 67 | + |
| 68 | + MemZaGram save = repository.save(memz.toBuilder().title(title).description(description).updatedDate(new Date()) |
| 69 | + .visible(visible).dateOfVisibility(dateOfVisibility).imageUploadId(imageUploadId) |
| 70 | + .thumbnailUploadId(thumbnailUploadId).build()); |
| 71 | + notificationService.sendEvent("memz %s added or updated".formatted(save.getTitle()), MEMZ_ADDED, save.getId()); |
| 72 | + } |
| 73 | + |
| 74 | + public Page<MemZaGram> findByVisibleIsTrueOrderByCreatedDateDesc(Pageable pageable) { |
| 75 | + return repository.findByVisibleIsTrueOrderByCreatedDateDesc(pageable); |
| 76 | + } |
| 77 | + |
| 78 | + public Page<MemZaGram> findAll(Pageable pageable) { |
| 79 | + return repository.findAll(pageable); |
| 80 | + } |
| 81 | + |
| 82 | + private String uploadAndDeleteIfExist(MultipartFile file, String id, String uploadId, Boolean visibility) { |
| 83 | + String newUploadId; |
| 84 | + Optional<String> optionalImageUploadId = ofNullable(file).filter(Predicate.not(MultipartFile::isEmpty)) |
| 85 | + .map(upload -> this.fileUploadService.upload(upload, id, TRUE.equals(visibility))); |
| 86 | + |
| 87 | + if (optionalImageUploadId.isEmpty()) { |
| 88 | + newUploadId = ofNullable(uploadId) |
| 89 | + .flatMap(uplId -> fileUploadService.updateVisibility(uplId, id, TRUE.equals(visibility))) |
| 90 | + .orElseThrow(() -> new RuntimeException("You cannot save without an image!")); |
| 91 | + } else { |
| 92 | + newUploadId = optionalImageUploadId.get(); |
| 93 | + ofNullable(uploadId).ifPresent(fileUploadService::delete); |
157 | 94 | } |
| 95 | + return newUploadId; |
| 96 | + } |
| 97 | + |
| 98 | + @Async |
| 99 | + public void delete(String id) { |
| 100 | + repository.findById(id).ifPresent(memz -> { |
| 101 | + fileUploadService.deleteByCorrelationId(id); |
| 102 | + repository.delete(memz); |
| 103 | + notificationService.sendEvent("memz %s deleted".formatted(memz.getTitle()), MEMZ_DELETED, memz.getId()); |
| 104 | + }); |
| 105 | + } |
| 106 | + |
| 107 | + public void incrementViewsCount(String id) { |
| 108 | + repository.findById(id) |
| 109 | + .map(memZaGram -> memZaGram.toBuilder().viewsCount(memZaGram.getViewsCount() + 1).build()) |
| 110 | + .ifPresent(repository::save); |
| 111 | + } |
| 112 | + |
| 113 | + @Override |
| 114 | + @CachePut(cacheNames = "memz_correlation_links", key = "#correlationId") |
| 115 | + public String getCorrelationLabel(String correlationId) { |
| 116 | + return this.repository.findById(correlationId).map(toLabel()).orElse(null); |
| 117 | + } |
| 118 | + |
| 119 | + private Function<? super MemZaGram, ? extends String> toLabel() { |
| 120 | + return mem -> "Memz '%s' ".formatted(mem.getTitle()); |
| 121 | + } |
| 122 | + |
| 123 | + @Override |
| 124 | + @CachePut(cacheNames = "memz_all_correlation_links", key = "'allLinks'") |
| 125 | + public Map<String, String> getCorrelationLabels(Collection<String> correlationIds) { |
| 126 | + return this.repository.findAllById(correlationIds).stream() |
| 127 | + .map(f -> Map.entry(f.getId(), this.toLabel().apply(f))) |
| 128 | + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); |
| 129 | + } |
| 130 | + |
| 131 | + @Override |
| 132 | + public void updateOldId(String correlationId, String oldId, String newId) { |
| 133 | + this.repository.findById(correlationId).ifPresent(p -> { |
| 134 | + var changed = false; |
| 135 | + if (oldId.equals(p.getImageUploadId())) { |
| 136 | + p.setImageUploadId(newId); |
| 137 | + changed = true; |
| 138 | + } |
| 139 | + if (oldId.equals(p.getThumbnailUploadId())) { |
| 140 | + p.setThumbnailUploadId(newId); |
| 141 | + changed = true; |
| 142 | + } |
| 143 | + if (changed) { |
| 144 | + this.repository.save(p.toBuilder().updatedDate(new Date()).build()); |
| 145 | + } |
| 146 | + }); |
| 147 | + |
| 148 | + } |
158 | 149 | } |
0 commit comments