From 41385a1c0dcb74a68abdecf154fbc25cbecf6e6a Mon Sep 17 00:00:00 2001 From: Tamas Bunth <tamas.bunth@collabora.co.uk> Date: Sat, 17 Feb 2018 22:41:53 +0100 Subject: [PATCH] Delete example rest API / data --- src/main/kotlin/mobildata/model/Article.kt | 22 -- src/main/kotlin/mobildata/model/Comment.kt | 15 -- src/main/kotlin/mobildata/model/Tag.kt | 13 - .../kotlin/mobildata/model/inout/Article.kt | 39 --- .../kotlin/mobildata/model/inout/Comment.kt | 30 --- .../mobildata/model/inout/NewArticle.kt | 22 -- .../mobildata/model/inout/NewComment.kt | 12 - .../mobildata/model/inout/UpdateArticle.kt | 9 - .../mobildata/repository/ArticleRepository.kt | 14 - .../mobildata/repository/CommentRepository.kt | 12 - .../mobildata/repository/TagRepository.kt | 10 - .../specification/ArticlesSpecifications.kt | 32 --- .../kotlin/mobildata/web/ArticleHandler.kt | 248 ------------------ src/main/resources/application.properties | 7 +- 14 files changed, 4 insertions(+), 481 deletions(-) delete mode 100644 src/main/kotlin/mobildata/model/Article.kt delete mode 100644 src/main/kotlin/mobildata/model/Comment.kt delete mode 100644 src/main/kotlin/mobildata/model/Tag.kt delete mode 100644 src/main/kotlin/mobildata/model/inout/Article.kt delete mode 100644 src/main/kotlin/mobildata/model/inout/Comment.kt delete mode 100644 src/main/kotlin/mobildata/model/inout/NewArticle.kt delete mode 100644 src/main/kotlin/mobildata/model/inout/NewComment.kt delete mode 100644 src/main/kotlin/mobildata/model/inout/UpdateArticle.kt delete mode 100644 src/main/kotlin/mobildata/repository/ArticleRepository.kt delete mode 100644 src/main/kotlin/mobildata/repository/CommentRepository.kt delete mode 100644 src/main/kotlin/mobildata/repository/TagRepository.kt delete mode 100644 src/main/kotlin/mobildata/repository/specification/ArticlesSpecifications.kt delete mode 100644 src/main/kotlin/mobildata/web/ArticleHandler.kt diff --git a/src/main/kotlin/mobildata/model/Article.kt b/src/main/kotlin/mobildata/model/Article.kt deleted file mode 100644 index 3552678..0000000 --- a/src/main/kotlin/mobildata/model/Article.kt +++ /dev/null @@ -1,22 +0,0 @@ -package mobildata.model - -import java.time.OffsetDateTime -import javax.persistence.* - -@Entity -data class Article(var slug: String = "", - var title: String = "", - var description: String = "", - var body: String = "", - @ManyToMany - val tagList: MutableList<Tag> = mutableListOf(), - var createdAt: OffsetDateTime = OffsetDateTime.now(), - var updatedAt: OffsetDateTime = OffsetDateTime.now(), - @ManyToMany - var favorited: MutableList<User> = mutableListOf(), - @ManyToOne - var author: User = User(), - @Id @GeneratedValue(strategy = GenerationType.AUTO) - var id: Long = 0) { - fun favoritesCount() = favorited.size -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/Comment.kt b/src/main/kotlin/mobildata/model/Comment.kt deleted file mode 100644 index 84e0321..0000000 --- a/src/main/kotlin/mobildata/model/Comment.kt +++ /dev/null @@ -1,15 +0,0 @@ -package mobildata.model - -import java.time.OffsetDateTime -import javax.persistence.* - -@Entity -data class Comment(var createdAt: OffsetDateTime = OffsetDateTime.now(), - var updatedAt: OffsetDateTime = OffsetDateTime.now(), - var body: String = "", - @ManyToOne - var article: Article = Article(), - @ManyToOne - var author: User = User(), - @Id @GeneratedValue(strategy = GenerationType.AUTO) - var id: Long = 0) \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/Tag.kt b/src/main/kotlin/mobildata/model/Tag.kt deleted file mode 100644 index c746e15..0000000 --- a/src/main/kotlin/mobildata/model/Tag.kt +++ /dev/null @@ -1,13 +0,0 @@ -package mobildata.model - -import com.fasterxml.jackson.annotation.JsonIgnore -import javax.persistence.Entity -import javax.persistence.GeneratedValue -import javax.persistence.GenerationType -import javax.persistence.Id - -@Entity -data class Tag(val name: String = "", - @Id @GeneratedValue(strategy = GenerationType.AUTO) - @JsonIgnore - var id: Long = 0) \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/inout/Article.kt b/src/main/kotlin/mobildata/model/inout/Article.kt deleted file mode 100644 index b43cee7..0000000 --- a/src/main/kotlin/mobildata/model/inout/Article.kt +++ /dev/null @@ -1,39 +0,0 @@ -package mobildata.model.inout - -import com.fasterxml.jackson.annotation.JsonRootName -import mobildata.model.User -import java.time.OffsetDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter - -@JsonRootName("article") -data class Article(var title: String? = null, - var description: String? = null, - var body: String? = null, - var tagList: List<String> = listOf(), - var slug: String = "", - var createdAt: String = "", - var updatedAt: String = "", - var author: Profile = Profile(username = "", bio = "", image = "", following = false), - var favorited: Boolean = false, - var favoritesCount: Int = 0) { - companion object { - fun dateFormat(date: OffsetDateTime): String { - return date.toZonedDateTime().withZoneSameInstant(ZoneId.of("Z")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME) - } - - fun fromModel(model: mobildata.model.Article, currentUser: User): Article { - return Article( - slug = model.slug, - title = model.title, - description = model.description, - body = model.body, - tagList = model.tagList.map { it.name }, - createdAt = dateFormat(model.createdAt), - updatedAt = dateFormat(model.updatedAt), - author = Profile.fromUser(model.author, currentUser), - favorited = model.favorited.contains(currentUser), - favoritesCount = model.favorited.size) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/inout/Comment.kt b/src/main/kotlin/mobildata/model/inout/Comment.kt deleted file mode 100644 index fbb34c0..0000000 --- a/src/main/kotlin/mobildata/model/inout/Comment.kt +++ /dev/null @@ -1,30 +0,0 @@ -package mobildata.model.inout - -import com.fasterxml.jackson.annotation.JsonRootName -import mobildata.model.User -import java.time.OffsetDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter - -@JsonRootName("comment") -data class Comment(val createdAt: String, - val updatedAt: String, - val body: String, - val author: Profile, - val id: Long) { - companion object { - fun dateFormat(date: OffsetDateTime): String { - return date.toZonedDateTime().withZoneSameInstant(ZoneId.of("Z")).format(DateTimeFormatter.ISO_ZONED_DATE_TIME) - } - - fun fromModel(model: mobildata.model.Comment, currentUser: User): Comment { - return Comment( - id = model.id, - body = model.body, - createdAt = dateFormat(model.createdAt), - updatedAt = dateFormat(model.updatedAt), - author = Profile.fromUser(model.author, currentUser) - ) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/inout/NewArticle.kt b/src/main/kotlin/mobildata/model/inout/NewArticle.kt deleted file mode 100644 index 2c3e267..0000000 --- a/src/main/kotlin/mobildata/model/inout/NewArticle.kt +++ /dev/null @@ -1,22 +0,0 @@ -package mobildata.model.inout - -import com.fasterxml.jackson.annotation.JsonRootName -import javax.validation.constraints.NotNull -import javax.validation.constraints.Size - -@JsonRootName("article") -class NewArticle { - @NotNull(message = "can't be missing") - @Size(min = 1, message = "can't be empty") - var title: String? = "" - - @NotNull(message = "can't be missing") - @Size(min = 1, message = "can't be empty") - var description: String? = "" - - @NotNull(message = "can't be missing") - @Size(min = 1, message = "can't be empty") - var body: String? = "" - - var tagList: List<String> = listOf() -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/inout/NewComment.kt b/src/main/kotlin/mobildata/model/inout/NewComment.kt deleted file mode 100644 index e4d6d2b..0000000 --- a/src/main/kotlin/mobildata/model/inout/NewComment.kt +++ /dev/null @@ -1,12 +0,0 @@ -package mobildata.model.inout - -import com.fasterxml.jackson.annotation.JsonRootName -import javax.validation.constraints.NotNull -import javax.validation.constraints.Size - -@JsonRootName("comment") -class NewComment { - @NotNull(message = "can't be missing") - @Size(min = 1, message = "can't be empty") - var body: String? = "" -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/model/inout/UpdateArticle.kt b/src/main/kotlin/mobildata/model/inout/UpdateArticle.kt deleted file mode 100644 index 0eed6fa..0000000 --- a/src/main/kotlin/mobildata/model/inout/UpdateArticle.kt +++ /dev/null @@ -1,9 +0,0 @@ -package mobildata.model.inout - -import com.fasterxml.jackson.annotation.JsonRootName - -@JsonRootName("article") -data class UpdateArticle(var title: String? = null, - var description: String? = null, - var body: String? = null, - var tagList: List<String>? = null) \ No newline at end of file diff --git a/src/main/kotlin/mobildata/repository/ArticleRepository.kt b/src/main/kotlin/mobildata/repository/ArticleRepository.kt deleted file mode 100644 index 0a85607..0000000 --- a/src/main/kotlin/mobildata/repository/ArticleRepository.kt +++ /dev/null @@ -1,14 +0,0 @@ -package mobildata.repository - -import mobildata.model.Article -import org.springframework.data.domain.Pageable -import org.springframework.data.jpa.repository.JpaSpecificationExecutor -import org.springframework.data.repository.PagingAndSortingRepository -import org.springframework.stereotype.Repository - -@Repository -interface ArticleRepository : PagingAndSortingRepository<Article, Long>, JpaSpecificationExecutor<Article> { - fun existsBySlug(slug: String): Boolean - fun findBySlug(slug: String): Article? - fun findByAuthorIdInOrderByCreatedAtDesc(ids: List<Long>, pageable: Pageable): List<Article> -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/repository/CommentRepository.kt b/src/main/kotlin/mobildata/repository/CommentRepository.kt deleted file mode 100644 index 2b61104..0000000 --- a/src/main/kotlin/mobildata/repository/CommentRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package mobildata.repository - -import mobildata.model.Article -import mobildata.model.Comment -import org.springframework.data.repository.CrudRepository -import org.springframework.stereotype.Repository - -@Repository -interface CommentRepository : CrudRepository<Comment, Long> { - fun findByArticle(article: Article): List<Comment> - fun findByArticleOrderByCreatedAtDesc(article: Article): List<Comment> -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/repository/TagRepository.kt b/src/main/kotlin/mobildata/repository/TagRepository.kt deleted file mode 100644 index 1188bbf..0000000 --- a/src/main/kotlin/mobildata/repository/TagRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package mobildata.repository - -import mobildata.model.Tag -import org.springframework.data.repository.CrudRepository -import org.springframework.stereotype.Repository - -@Repository -interface TagRepository : CrudRepository<Tag, Long> { - fun findByName(name: String): Tag? -} \ No newline at end of file diff --git a/src/main/kotlin/mobildata/repository/specification/ArticlesSpecifications.kt b/src/main/kotlin/mobildata/repository/specification/ArticlesSpecifications.kt deleted file mode 100644 index dddfa4d..0000000 --- a/src/main/kotlin/mobildata/repository/specification/ArticlesSpecifications.kt +++ /dev/null @@ -1,32 +0,0 @@ -package mobildata.repository.specification - -import mobildata.model.Article -import mobildata.model.Tag -import mobildata.model.User -import org.springframework.data.jpa.domain.Specification -import javax.persistence.criteria.Predicate - -object ArticlesSpecifications { - fun lastArticles(tag: Tag?, author: User?, fav: User?): Specification<Article> { - return Specification { root, query, cb -> - val predicates = mutableListOf<Predicate>() - - tag?.let { - val tagList = root.get<Collection<Tag>>("tagList") - predicates.add(cb.isMember(tag, tagList)) - } - - author?.let { - val user = root.get<String>("author") - predicates.add(cb.equal(user, author)) - } - - fav?.let { - val favorited = root.get<Collection<User>>("favorited") - predicates.add(cb.isMember(fav, favorited)) - } - - cb.and(*predicates.toTypedArray()) - } - } -} diff --git a/src/main/kotlin/mobildata/web/ArticleHandler.kt b/src/main/kotlin/mobildata/web/ArticleHandler.kt deleted file mode 100644 index 62fa278..0000000 --- a/src/main/kotlin/mobildata/web/ArticleHandler.kt +++ /dev/null @@ -1,248 +0,0 @@ -package mobildata.web - -import com.github.slugify.Slugify -import mobildata.exception.ForbiddenRequestException -import mobildata.exception.InvalidRequest -import mobildata.exception.NotFoundException -import mobildata.jwt.ApiKeySecured -import mobildata.model.Article -import mobildata.model.Comment -import mobildata.model.Tag -import mobildata.model.User -import mobildata.model.inout.NewArticle -import mobildata.model.inout.NewComment -import mobildata.model.inout.UpdateArticle -import mobildata.repository.ArticleRepository -import mobildata.repository.CommentRepository -import mobildata.repository.TagRepository -import mobildata.repository.UserRepository -import mobildata.repository.specification.ArticlesSpecifications -import mobildata.service.UserService -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Sort -import org.springframework.http.HttpStatus -import org.springframework.validation.Errors -import org.springframework.validation.FieldError -import org.springframework.web.bind.annotation.* -import java.time.OffsetDateTime -import java.util.* -import javax.validation.Valid -import mobildata.model.inout.Article as ArticleIO -import mobildata.model.inout.Comment as CommentOut - -@RestController -class ArticleHandler(val repository: ArticleRepository, - val userService: UserService, - val userRepository: UserRepository, - val commentRepository: CommentRepository, - val tagRepository: TagRepository) { -/* - @ApiKeySecured(mandatory = false) - @GetMapping("/api/articles") - fun articles(@RequestParam(defaultValue = "20") limit: Int, - @RequestParam(defaultValue = "0") offset: Int, - @RequestParam(defaultValue = "") tag: String, - @RequestParam(defaultValue = "") author: String, - @RequestParam(defaultValue = "") favorited: String): Any { - val p = PageRequest.of(offset, limit, Sort.Direction.DESC, "createdAt") - - val articles = repository.findAll(ArticlesSpecifications.lastArticles( - if (tag != "") tagRepository.findByName(tag) else null, - if (author != "") userRepository.findByUsername(author) else null, - if (favorited != "") userRepository.findByUsername(favorited) else null - ), p).toList() - - return articlesView(articles, userService.currentUser()) - } - - - @ApiKeySecured - @GetMapping("/api/articles/feed") - fun feed(@RequestParam(defaultValue = "20") limit: Int, - @RequestParam(defaultValue = "0") offset: Int): Any { - val currentUser = userService.currentUser() - val articles = repository.findByAuthorIdInOrderByCreatedAtDesc(currentUser.follows.map { it.id }, - PageRequest.of(offset, limit)) - return articlesView(articles, currentUser) - } - - @ApiKeySecured(mandatory = false) - @GetMapping("/api/articles/{slug}") - fun article(@PathVariable slug: String): Any { - repository.findBySlug(slug)?.let { - return articleView(it, userService.currentUser()) - } - throw NotFoundException() - } -*/ - @ApiKeySecured - @PostMapping("/api/articles") - fun newArticle(@Valid @RequestBody newArticle: NewArticle, errors: Errors): Any { - InvalidRequest.check(errors) - - var slug = Slugify().slugify(newArticle.title!!) - - if (repository.existsBySlug(slug)) { - slug += "-" + UUID.randomUUID().toString().substring(0, 8) - } - - val currentUser = userService.currentUser() - - // search for tags - val tagList = newArticle.tagList.map { - tagRepository.findByName(it) ?: tagRepository.save(Tag(name = it)) - } - - val article = Article(slug = slug, - author = currentUser, title = newArticle.title!!, description = newArticle.description!!, - body = newArticle.body!!, tagList = tagList.toMutableList()) - - return articleView(repository.save(article), currentUser) - } -/* - @ApiKeySecured - @PutMapping("/api/articles/{slug}") - fun updateArticle(@PathVariable slug: String, @RequestBody article: UpdateArticle): Any { - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - if (it.author.id != currentUser.id) - throw ForbiddenRequestException() - - // check for errors - val errors = org.springframework.validation.BindException(this, "") - if (article.title == "") - errors.addError(FieldError("", "title", "can't be empty")) - if (article.description == "") - errors.addError(FieldError("", "description", "can't be empty")) - if (article.body == "") - errors.addError(FieldError("", "body", "can't be empty")) - InvalidRequest.check(errors) - - var slug: String = it.slug - article.title?.let { newTitle -> - if (newTitle != it.title) { - // we don't want conflicting slugs - slug = Slugify().slugify(article.title!!) - if (repository.existsBySlug(slug)) { - slug += "-" + UUID.randomUUID().toString().substring(0, 8) - } - } - } - - // search for tags - val tagList = article.tagList?.map { - tagRepository.findByName(it) ?: tagRepository.save(Tag(name = it)) - } - - val updated = it.copy(title = article.title ?: it.title, - description = article.description ?: it.description, - body = article.body ?: it.body, - slug = slug, - updatedAt = OffsetDateTime.now(), - tagList = if (tagList == null || tagList.isEmpty()) it.tagList - else tagList.toMutableList()) - - return articleView(repository.save(updated), currentUser) - } - - throw NotFoundException() - } - - @ApiKeySecured - @ResponseStatus(HttpStatus.OK) - @DeleteMapping("/api/articles/{slug}") - fun deleteArticle(@PathVariable slug: String) { - repository.findBySlug(slug)?.let { - if (it.author.id != userService.currentUser().id) - throw ForbiddenRequestException() - - commentRepository.deleteAll(commentRepository.findByArticle(it)) - return repository.delete(it) - } - throw NotFoundException() - } - - @ApiKeySecured(mandatory = false) - @GetMapping("/api/articles/{slug}/comments") - fun articleComments(@PathVariable slug: String): Any { - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - return commentsView(commentRepository.findByArticleOrderByCreatedAtDesc(it), currentUser) - } - throw NotFoundException() - } - - @ApiKeySecured - @PostMapping("/api/articles/{slug}/comments") - fun addComment(@PathVariable slug: String, @Valid @RequestBody comment: NewComment, errors: Errors): Any { - InvalidRequest.check(errors) - - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - val newComment = Comment(body = comment.body!!, article = it, author = currentUser) - return commentView(commentRepository.save(newComment), currentUser) - } - throw NotFoundException() - } - - @ApiKeySecured - @ResponseStatus(HttpStatus.OK) - @DeleteMapping("/api/articles/{slug}/comments/{id}") - fun deleteComment(@PathVariable slug: String, @PathVariable id: Long) { - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - val comment = commentRepository.findById(id).orElseThrow({ NotFoundException() }) - if (comment.article.id != it.id) - throw ForbiddenRequestException() - if (comment.author.id != currentUser.id) - throw ForbiddenRequestException() - - return commentRepository.delete(comment) - } - throw NotFoundException() - } - - @ApiKeySecured - @PostMapping("/api/articles/{slug}/favorite") - fun favoriteArticle(@PathVariable slug: String): Any { - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - if (!it.favorited.contains(currentUser)) { - it.favorited.add(currentUser) - return articleView(repository.save(it), currentUser) - } - return articleView(it, currentUser) - } - throw NotFoundException() - } - - @ApiKeySecured - @DeleteMapping("/api/articles/{slug}/favorite") - fun unfavoriteArticle(@PathVariable slug: String): Any { - repository.findBySlug(slug)?.let { - val currentUser = userService.currentUser() - if (it.favorited.contains(currentUser)) { - it.favorited.remove(currentUser) - return articleView(repository.save(it), currentUser) - } - return articleView(it, currentUser) - } - throw NotFoundException() - } -*/ - // helpers - - fun articleView(article: Article, currentUser: User) - = mapOf("article" to ArticleIO.fromModel(article, currentUser)) -/* - fun articlesView(articles: List<Article>, currentUser: User) - = mapOf("articles" to articles.map { ArticleIO.fromModel(it, userService.currentUser()) }, - "articlesCount" to articles.size) - - fun commentView(comment: Comment, currentUser: User) - = mapOf("comment" to CommentOut.fromModel(comment, currentUser)) - - fun commentsView(comments: List<Comment>, currentUser: User) - = mapOf("comments" to comments.map { CommentOut.fromModel(it, currentUser) }) -*/ -} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ff374d8..583c14d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,10 +5,11 @@ spring.datasource.password=postgres spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect -# create schema automatically. It can be more fine-grained with the commented stuff below. -# spring.jpa.generate-ddl=true +# Every time the modell changes, there should be a run with "generate-ddl=true -# recreate the database on startup +## create schema automatically. It can be more fine-grained with the commented stuff below. +# spring.jpa.generate-ddl=true +## recreate the database on startup spring.jpa.hibernate.ddl-auto=create-drop # restart server: -- GitLab