package be.simplenotes.domain.usecases import arrow.core.Either import arrow.core.extensions.fx import be.simplenotes.domain.model.Note import be.simplenotes.domain.model.PersistedNote import be.simplenotes.domain.model.PersistedNoteMetadata import be.simplenotes.domain.security.HtmlSanitizer import be.simplenotes.domain.usecases.markdown.MarkdownConverter import be.simplenotes.domain.usecases.markdown.MarkdownParsingError import be.simplenotes.domain.usecases.repositories.NoteRepository import be.simplenotes.domain.usecases.repositories.UserRepository import be.simplenotes.domain.usecases.search.NoteSearcher import be.simplenotes.domain.usecases.search.SearchTerms import java.util.* class NoteService( private val markdownConverter: MarkdownConverter, private val noteRepository: NoteRepository, private val userRepository: UserRepository, private val searcher: NoteSearcher, ) { fun create(userId: Int, markdownText: String) = Either.fx { val persistedNote = !markdownConverter.renderDocument(markdownText) .map { it.copy(html = HtmlSanitizer.sanitize(it.html)) } .map { Note(it.metadata, markdown = markdownText, html = it.html) } .map { noteRepository.create(userId, it) } searcher.indexNote(userId, persistedNote) persistedNote } fun update(userId: Int, uuid: UUID, markdownText: String) = Either.fx { val persistedNote = !markdownConverter.renderDocument(markdownText) .map { it.copy(html = HtmlSanitizer.sanitize(it.html)) } .map { Note(it.metadata, markdown = markdownText, html = it.html) } .map { noteRepository.update(userId, uuid, it) } persistedNote?.let { searcher.updateIndex(userId, it) } persistedNote } fun paginatedNotes( userId: Int, page: Int, itemsPerPage: Int = 20, tag: String? = null, deleted: Boolean = false, ): PaginatedNotes { val count = noteRepository.count(userId, tag, deleted) val offset = (page - 1) * itemsPerPage val numberOfPages = (count / itemsPerPage) + 1 val notes = if (count == 0) emptyList() else noteRepository.findAll(userId, itemsPerPage, offset, tag, deleted) return PaginatedNotes(numberOfPages, notes) } fun find(userId: Int, uuid: UUID) = noteRepository.find(userId, uuid) fun trash(userId: Int, uuid: UUID): Boolean { val res = noteRepository.delete(userId, uuid, permanent = false) if (res) searcher.deleteIndex(userId, uuid) return res } fun restore(userId: Int, uuid: UUID): Boolean { val res = noteRepository.restore(userId, uuid) if (res) find(userId, uuid)?.let { note -> searcher.indexNote(userId, note) } return res } fun delete(userId: Int, uuid: UUID): Boolean { val res = noteRepository.delete(userId, uuid, permanent = true) if (res) searcher.deleteIndex(userId, uuid) return res } fun countDeleted(userId: Int) = noteRepository.count(userId, deleted = true) fun indexAll() { val userIds = userRepository.findAll() userIds.forEach { id -> val notes = noteRepository.findAllDetails(id) searcher.indexNotes(id, notes) } } fun search(userId: Int, searchTerms: SearchTerms) = searcher.search(userId, searchTerms) fun dropAllIndexes() = searcher.dropAll() fun makePublic(userId: Int, uuid: UUID) = noteRepository.makePublic(userId, uuid) fun makePrivate(userId: Int, uuid: UUID) = noteRepository.makePrivate(userId, uuid) fun findPublic(uuid: UUID) = noteRepository.findPublic(uuid) } data class PaginatedNotes(val pages: Int, val notes: List)