───────┬──────────────────────────────────────────────────────────────────────── │ File: src/main//java/jp/ac/kobe_u/cs/itspecialist/todoapp/service/ToDoService.java ───────┼──────────────────────────────────────────────────────────────────────── 1 │ package jp.ac.kobe_u.cs.itspecialist.todoapp.service; 2 │ 3 │ import java.util.*; 4 │ 5 │ import java.util.function.BiFunction; 6 │ import java.util.function.Function; 7 │ 8 │ import jp.ac.kobe_u.cs.itspecialist.todoapp.TriFunction; 9 │ import org.springframework.beans.factory.annotation.Autowired; 10 │ import org.springframework.data.util.Pair; 11 │ import org.springframework.data.domain.Page; 12 │ import org.springframework.data.domain.Pageable; 13 │ import org.springframework.stereotype.Service; 14 │ 15 │ import jp.ac.kobe_u.cs.itspecialist.todoapp.dto.ToDoForm; 16 │ import jp.ac.kobe_u.cs.itspecialist.todoapp.entity.ToDo; 17 │ import jp.ac.kobe_u.cs.itspecialist.todoapp.exception.ToDoAppException; 18 │ import jp.ac.kobe_u.cs.itspecialist.todoapp.repository.ToDoRepository; 19 │ 20 │ @Service 21 │ public class ToDoService { 22 │ @Autowired 23 │ MemberService mService; 24 │ @Autowired 25 │ ToDoRepository tRepo; 26 │ /** 27 │ * ToDoを作成する (C) 28 │ * @param mid 作成者 29 │ * @param form フォーム 30 │ * @return 31 │ */ 32 │ public ToDo createToDo(String mid, ToDoForm form) { 33 │ mService.getMember(mid); //実在メンバーか確認 34 │ ToDo todo = form.toEntity(); 35 │ if(!todo.isValidDueDate()) { 36 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, 37 │ todo.getDueAt() + ": should be after created at"); 38 │ } 39 │ todo.setMid(mid); 40 │ return tRepo.save(todo); 41 │ } 42 │ 43 │ /** 44 │ * ToDoを1つ取得する (R) 45 │ * @param seq 46 │ * @return 47 │ */ 48 │ public ToDo getToDo(Long seq) { 49 │ ToDo todo = tRepo.findById(seq).orElseThrow( 50 │ () -> new ToDoAppException(ToDoAppException.NO_SUCH_TODO_EXISTS, 51 │ seq + ": No such ToDo exists") 52 │ ); 53 │ return todo; 54 │ } 55 │ 56 │ public Page<ToDo> getToDoAllList(String mid, Pageable pageable) { 57 │ return tRepo.findByMidAndDone(mid, false, pageable); 58 │ } 59 │ 60 │ /** 61 │ * あるメンバーのToDoリストを取得する (R) 62 │ * @param mid 63 │ * @return 64 │ */ 65 │ public Page<ToDo> getToDoList(String mid, String sortBy, String order, Pageable pageable) { 66 │ TriFunction<String, Boolean, Pageable, Page<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order), 67 │ (memberId, doneFlag, pageable2) -> tRepo.findByMidAndDone(memberId, doneFlag, pageable2)); 68 │ return finder.apply(mid, false, pageable); 69 │ } 70 │ 71 │ public Page<ToDo> getDoneAllList(String mid, Pageable pageable) { 72 │ return tRepo.findByMidAndDone(mid, true, pageable); 73 │ } 74 │ 75 │ /** 76 │ * あるメンバーのDoneリストを取得する (R) 77 │ * @param mid 78 │ * @return 79 │ */ 80 │ public Page<ToDo> getDoneList(String mid, String sortBy, String order, Pageable pageable) { 81 │ TriFunction<String, Boolean, Pageable, Page<ToDo>> finder = midAndDoneFinder.getOrDefault(Pair.of(sortBy, order), 82 │ (memberId, doneFlag, pageable2) -> tRepo.findByMidAndDone(memberId, doneFlag, pageable2)); 83 │ return finder.apply(mid, true, pageable); 84 │ } 85 │ 86 │ private final Map<Pair<String, String>, TriFunction<String, Boolean, Pageable, Page<ToDo>>> midAndDoneFinder = generateMidAndDoneFinder(); 87 │ private Map<Pair<String, String>, TriFunction<String, Boolean, Pageable, Page<ToDo>>> generateMidAndDoneFinder() { 88 │ Map<Pair<String, String>, TriFunction<String, Boolean, Pageable, Page<ToDo>>> map = new HashMap<>(); 89 │ map.put(Pair.of("seq", "asc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderBySeqAsc(mid, done, pageable)); 90 │ map.put(Pair.of("seq", "desc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderBySeqDesc(mid, done, pageable)); 91 │ map.put(Pair.of("title", "asc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByTitleAsc(mid, done, pageable)); 92 │ map.put(Pair.of("title", "desc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByTitleDesc(mid, done, pageable)); 93 │ map.put(Pair.of("created_at", "asc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByCreatedAtAsc(mid, done, pageable)); 94 │ map.put(Pair.of("created_at", "desc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByCreatedAtDesc(mid, done, pageable)); 95 │ map.put(Pair.of("done_at", "asc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByDoneAtAsc(mid, done, pageable)); 96 │ map.put(Pair.of("done_at", "desc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByDoneAtDesc(mid, done, pageable)); 97 │ map.put(Pair.of("due_at", "asc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByDueAtAsc(mid, done, pageable)); 98 │ map.put(Pair.of("due_at", "desc"), (mid, done, pageable) -> tRepo.findByMidAndDoneOrderByDueAtDesc(mid, done, pageable)); 99 │ return map; 100 │ } 101 │ 102 │ /** 103 │ * 全員のToDoリストを取得する (R) 104 │ * @return 105 │ */ 106 │ public Page<ToDo> getToDoList(String sortBy, String order, Pageable pageable) { 107 │ BiFunction<Boolean, Pageable, Page<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order), 108 │ (doneFlag, pageable2) -> tRepo.findByDone(doneFlag, pageable2)); 109 │ return finder.apply(false, pageable); 110 │ } 111 │ 112 │ /** 113 │ * 全員のDoneリストを取得する (R) 114 │ * @return 115 │ */ 116 │ public Page<ToDo> getDoneList(String sortBy, String order, Pageable pageable) { 117 │ BiFunction<Boolean, Pageable, Page<ToDo>> finder = doneFinder.getOrDefault(Pair.of(sortBy, order), 118 │ (doneFlag, pageable2) -> tRepo.findByDone(doneFlag, pageable2)); 119 │ return finder.apply(true, pageable); 120 │ } 121 │ 122 │ /** 123 │ * 〆切を更新する. 124 │ * @param mid 125 │ * @param seq 126 │ * @param due 127 │ */ 128 │ public ToDo updateDueDate(String mid, Long seq, Date due) { 129 │ ToDo todo = getToDo(seq); 130 │ if (!Objects.equals(mid, todo.getMid())) { 131 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 132 │ + ": Cannot done other's todo of " + todo.getMid()); 133 │ } 134 │ if (due != null && due.before(todo.getCreatedAt())) { 135 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, 136 │ due + ": should be after created at."); 137 │ } 138 │ todo.setDueAt(due); 139 │ return tRepo.save(todo); 140 │ } 141 │ 142 │ private final Map<Pair<String, String>, BiFunction<Boolean, Pageable, Page<ToDo>>> doneFinder = generateDoneFinder(); 143 │ private Map<Pair<String, String>, BiFunction<Boolean, Pageable, Page<ToDo>>> generateDoneFinder() { 144 │ Map<Pair<String, String>, BiFunction<Boolean, Pageable, Page<ToDo>>> map = new HashMap<>(); 145 │ map.put(Pair.of("seq", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderBySeqAsc(doneFlag, pageable)); 146 │ map.put(Pair.of("seq", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderBySeqDesc(doneFlag, pageable)); 147 │ map.put(Pair.of("title", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByTitleAsc(doneFlag, pageable)); 148 │ map.put(Pair.of("title", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByTitleDesc(doneFlag, pageable)); 149 │ map.put(Pair.of("mid", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByMidAsc(doneFlag, pageable)); 150 │ map.put(Pair.of("mid", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByMidDesc(doneFlag, pageable)); 151 │ map.put(Pair.of("created_at", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByCreatedAtAsc(doneFlag, pageable)); 152 │ map.put(Pair.of("created_at", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByCreatedAtDesc(doneFlag, pageable)); 153 │ map.put(Pair.of("done_at", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByDoneAtAsc(doneFlag, pageable)); 154 │ map.put(Pair.of("done_at", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByDoneAtDesc(doneFlag, pageable)); 155 │ map.put(Pair.of("due_at", "asc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByDueAtAsc(doneFlag, pageable)); 156 │ map.put(Pair.of("due_at", "desc"), (doneFlag, pageable) -> tRepo.findByDoneOrderByDueAtDesc(doneFlag, pageable)); 157 │ return map; 158 │ } 159 │ 160 │ /** 161 │ * ToDoを完了する 162 │ * @param mid 完了者 163 │ * @param seq 完了するToDoの番号 164 │ * @return 165 │ */ 166 │ public ToDo done(String mid, Long seq) { 167 │ ToDo todo = getToDo(seq); 168 │ //Doneの認可を確認する.他人のToDoを閉めたらダメ. 169 │ if (!mid.equals(todo.getMid())) { 170 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 171 │ + ": Cannot done other's todo of " + todo.getMid()); 172 │ } 173 │ todo.setDone(true); 174 │ todo.setDoneAt(new Date()); 175 │ return tRepo.save(todo); 176 │ } 177 │ 178 │ /** 179 │ * ToDo の完了をキャンセルする. 180 │ * @param mid 完了者 181 │ * @param seq 完了をキャンセルするToDoの番号 182 │ * @return 183 │ */ 184 │ public ToDo cancel(String mid, Long seq) { 185 │ ToDo todo = getToDo(seq); 186 │ // Doneの認可を確認する.他人のToDoを閉めたらダメ. 187 │ if (!mid.equals(todo.getMid())) { 188 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, 189 │ mid + ": Cannot cancel other's todo of " + todo.getMid()); 190 │ } 191 │ todo.setDone(false); 192 │ todo.setDoneAt(null); 193 │ return tRepo.save(todo); 194 │ } 195 │ 196 │ /** 197 │ * ToDoを更新する 198 │ * @param mid 更新者 199 │ * @param seq 更新するToDo番号 200 │ * @param form 更新フォーム 201 │ * @return 202 │ */ 203 │ public ToDo updateToDo(String mid, Long seq, ToDoForm form) { 204 │ ToDo todo = getToDo(seq); 205 │ //Doneの認可を確認する.他人のToDoを更新したらダメ. 206 │ if (!mid.equals(todo.getMid())) { 207 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 208 │ + ": Cannot update other's todo of " + todo.getMid()); 209 │ } 210 │ todo.setTitle(form.getTitle()); //タイトルを更新 211 │ return tRepo.save(todo); 212 │ } 213 │ 214 │ /** 215 │ * 背景色を更新する. 216 │ * @param mid 更新者 217 │ * @param seq 更新するToDo番号 218 │ * @param background 新しい背景色 219 │ * @return 220 │ */ 221 │ public ToDo updateBackground(String mid, Long seq, String background) { 222 │ ToDo todo = getToDo(seq); 223 │ //Doneの認可を確認する.他人のToDoを更新したらダメ. 224 │ if (!mid.equals(todo.getMid())) { 225 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 226 │ + ": Cannot update other's todo of " + todo.getMid()); 227 │ } 228 │ todo.setBackground(background); 229 │ return tRepo.save(todo); 230 │ } 231 │ 232 │ /** 233 │ * ToDoを削除する 234 │ * @param mid 削除者 235 │ * @param seq 削除するToDo番号 236 │ */ 237 │ public void deleteToDo(String mid, Long seq) { 238 │ ToDo todo = getToDo(seq); 239 │ //Doneの認可を確認する.他人のToDoを削除したらダメ. 240 │ if (!mid.equals(todo.getMid())) { 241 │ throw new ToDoAppException(ToDoAppException.INVALID_TODO_OPERATION, mid 242 │ + ": Cannot delete other's todo of " + todo.getMid()); 243 │ } 244 │ tRepo.deleteById(seq); 245 │ } 246 │ 247 │ 248 │ 249 │ } ───────┴────────────────────────────────────────────────────────────────────────