├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ └── gradle.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.gradle ├── docs ├── -kotlin-inside │ ├── be.zvz.kotlininside.api.article │ │ ├── -article-delete │ │ │ ├── -article-delete.html │ │ │ ├── -delete-result │ │ │ │ ├── -delete-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── message.html │ │ │ │ ├── result.html │ │ │ │ └── status.html │ │ │ ├── delete.html │ │ │ └── index.html │ │ ├── -article-hit-upvote │ │ │ ├── -article-hit-upvote.html │ │ │ ├── -hit-upvote-result │ │ │ │ ├── -hit-upvote-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── index.html │ │ │ └── upvote.html │ │ ├── -article-list │ │ │ ├── -article-list.html │ │ │ ├── -gall-info │ │ │ │ ├── -gall-info.html │ │ │ │ ├── captcha.html │ │ │ │ ├── category.html │ │ │ │ ├── code-count.html │ │ │ │ ├── file-count.html │ │ │ │ ├── file-size.html │ │ │ │ ├── head-text.html │ │ │ │ ├── index.html │ │ │ │ ├── is-manager.html │ │ │ │ ├── is-mini.html │ │ │ │ ├── is-minor.html │ │ │ │ ├── member-join.html │ │ │ │ ├── membership.html │ │ │ │ ├── no-write.html │ │ │ │ ├── notify-recent.html │ │ │ │ ├── profile-image.html │ │ │ │ ├── relation-gall.html │ │ │ │ ├── title.html │ │ │ │ ├── total-member.html │ │ │ │ ├── use-auto-delete.html │ │ │ │ └── use-list-fix.html │ │ │ ├── -gall-list │ │ │ │ ├── -gall-list.html │ │ │ │ ├── best-check.html │ │ │ │ ├── date-time.html │ │ │ │ ├── galler-con.html │ │ │ │ ├── head-text.html │ │ │ │ ├── identifier.html │ │ │ │ ├── image-icon.html │ │ │ │ ├── index.html │ │ │ │ ├── ip.html │ │ │ │ ├── level.html │ │ │ │ ├── member-icon.html │ │ │ │ ├── name.html │ │ │ │ ├── subject.html │ │ │ │ ├── total-comment.html │ │ │ │ ├── total-voice.html │ │ │ │ ├── upvote-icon.html │ │ │ │ ├── upvote.html │ │ │ │ ├── user-id.html │ │ │ │ ├── views.html │ │ │ │ ├── voice-icon.html │ │ │ │ └── winnerta-icon.html │ │ │ ├── -search-type │ │ │ │ ├── -a-l-l │ │ │ │ │ └── index.html │ │ │ │ ├── -c-o-n-t-e-n-t │ │ │ │ │ └── index.html │ │ │ │ ├── -n-a-m-e │ │ │ │ │ └── index.html │ │ │ │ ├── -s-u-b-j-e-c-t │ │ │ │ │ └── index.html │ │ │ │ ├── -s-u-b-j-e-c-t_-a-n-d_-c-o-n-t-e-n-t │ │ │ │ │ └── index.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── type.html │ │ │ │ ├── value-of.html │ │ │ │ └── values.html │ │ │ ├── get-gall-info.html │ │ │ ├── get-gall-list.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -article-modify │ │ │ ├── -article-modify.html │ │ │ ├── -file-data │ │ │ │ ├── -file-data.html │ │ │ │ ├── block.html │ │ │ │ ├── file-size.html │ │ │ │ └── index.html │ │ │ ├── -modify-result │ │ │ │ ├── -modify-result.html │ │ │ │ ├── article-id.html │ │ │ │ ├── cause.html │ │ │ │ ├── content.html │ │ │ │ ├── current-head-text.html │ │ │ │ ├── file-count.html │ │ │ │ ├── file-size.html │ │ │ │ ├── file.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── head-text.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── subject.html │ │ │ ├── index.html │ │ │ ├── modify-info.html │ │ │ └── modify.html │ │ ├── -article-read │ │ │ ├── -article-read.html │ │ │ ├── -view-info │ │ │ │ ├── -view-info.html │ │ │ │ ├── best-check.html │ │ │ │ ├── category.html │ │ │ │ ├── comment-delete-scope.html │ │ │ │ ├── date-time.html │ │ │ │ ├── gall-title.html │ │ │ │ ├── galler-con.html │ │ │ │ ├── head-text.html │ │ │ │ ├── head-title.html │ │ │ │ ├── identifier.html │ │ │ │ ├── image-check.html │ │ │ │ ├── index.html │ │ │ │ ├── ip.html │ │ │ │ ├── is-mini.html │ │ │ │ ├── is-minor.html │ │ │ │ ├── is-notice.html │ │ │ │ ├── level.html │ │ │ │ ├── member-grant.html │ │ │ │ ├── member-icon.html │ │ │ │ ├── membership.html │ │ │ │ ├── name.html │ │ │ │ ├── next-link.html │ │ │ │ ├── next-subject.html │ │ │ │ ├── previous-link.html │ │ │ │ ├── previous-subject.html │ │ │ │ ├── recommend-check.html │ │ │ │ ├── subject.html │ │ │ │ ├── total-comment.html │ │ │ │ ├── use-auto-delete.html │ │ │ │ ├── use-list-fix.html │ │ │ │ ├── user-id.html │ │ │ │ ├── views.html │ │ │ │ ├── voice-check.html │ │ │ │ ├── winnerta-check.html │ │ │ │ └── write-type.html │ │ │ ├── -view-main │ │ │ │ ├── -view-main.html │ │ │ │ ├── content.html │ │ │ │ ├── downvote.html │ │ │ │ ├── index.html │ │ │ │ ├── is-manager.html │ │ │ │ ├── upvote-member.html │ │ │ │ └── upvote.html │ │ │ ├── get-view-info.html │ │ │ ├── get-view-main.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -article-report │ │ │ ├── -article-report.html │ │ │ ├── get-link.html │ │ │ └── index.html │ │ ├── -article-vote │ │ │ ├── -article-vote.html │ │ │ ├── -vote-result │ │ │ │ ├── -vote-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── member.html │ │ │ │ └── result.html │ │ │ ├── downvote.html │ │ │ ├── index.html │ │ │ └── upvote.html │ │ ├── -article-write │ │ │ ├── -article-write.html │ │ │ ├── -write-result │ │ │ │ ├── -write-result.html │ │ │ │ ├── article-id.html │ │ │ │ ├── cause.html │ │ │ │ ├── id.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── index.html │ │ │ └── write.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.article │ │ ├── -async-article-delete │ │ │ ├── -async-article-delete.html │ │ │ ├── delete-async.html │ │ │ └── index.html │ │ ├── -async-article-hit-upvote │ │ │ ├── -async-article-hit-upvote.html │ │ │ ├── index.html │ │ │ └── upvote-async.html │ │ ├── -async-article-list │ │ │ ├── -async-article-list.html │ │ │ ├── get-gall-info-async.html │ │ │ ├── get-gall-list-async.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-article-modify │ │ │ ├── -async-article-modify.html │ │ │ ├── index.html │ │ │ ├── modify-async.html │ │ │ └── modify-info-async.html │ │ ├── -async-article-read │ │ │ ├── -async-article-read.html │ │ │ ├── get-view-info-async.html │ │ │ ├── get-view-main-async.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-article-report │ │ │ ├── -async-article-report.html │ │ │ ├── get-link-async.html │ │ │ └── index.html │ │ ├── -async-article-vote │ │ │ ├── -async-article-vote.html │ │ │ ├── downvote-async.html │ │ │ ├── index.html │ │ │ └── upvote-async.html │ │ ├── -async-article-write │ │ │ ├── -async-article-write.html │ │ │ ├── index.html │ │ │ └── write-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.comment │ │ ├── -async-comment-delete │ │ │ ├── -async-comment-delete.html │ │ │ ├── delete-async.html │ │ │ └── index.html │ │ ├── -async-comment-read │ │ │ ├── -async-comment-read.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-comment-write │ │ │ ├── -async-comment-write.html │ │ │ ├── index.html │ │ │ ├── reply-async.html │ │ │ └── write-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.dccon │ │ ├── -async-d-c-con-buy │ │ │ ├── -async-d-c-con-buy.html │ │ │ ├── buy-async.html │ │ │ └── index.html │ │ ├── -async-d-c-con-detail │ │ │ ├── -async-d-c-con-detail.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-d-c-con-list │ │ │ ├── -async-d-c-con-list.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.generic.minigallery │ │ ├── -async-join-mini-gallery │ │ │ ├── -async-join-mini-gallery.html │ │ │ ├── index.html │ │ │ ├── join-async.html │ │ │ ├── request-member-join-async.html │ │ │ └── request-member-join-ok-async.html │ │ ├── -async-quit-mini-gallery │ │ │ ├── -async-quit-mini-gallery.html │ │ │ ├── index.html │ │ │ └── quit-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.generic.userinfo │ │ ├── -async-check-joined-mini-gallery │ │ │ ├── -async-check-joined-mini-gallery.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-check-managed-gallery │ │ │ ├── -async-check-managed-gallery.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-modify-my-gall │ │ │ ├── -async-modify-my-gall.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-my-gall │ │ │ ├── -async-my-gall.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.generic │ │ ├── -async-gallery-ranking │ │ │ ├── -async-gallery-ranking.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-gallery-search │ │ │ ├── -async-gallery-search.html │ │ │ ├── index.html │ │ │ └── search-async.html │ │ ├── -async-main-page │ │ │ ├── -async-main-page.html │ │ │ ├── get-best-async.html │ │ │ ├── get-hit-async.html │ │ │ ├── get-issue-zoom-async.html │ │ │ ├── get-new-gallery-async.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-mini-gallery-ranking │ │ │ ├── -async-mini-gallery-ranking.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-minor-gallery-info │ │ │ ├── -async-minor-gallery-info.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-minor-gallery-ranking │ │ │ ├── -async-minor-gallery-ranking.html │ │ │ ├── get-async.html │ │ │ └── index.html │ │ ├── -async-total-search │ │ │ ├── -async-total-search.html │ │ │ ├── index.html │ │ │ └── search-async.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.async.management │ │ ├── -async-change-head-text │ │ │ ├── -async-change-head-text.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-gallery-setting │ │ │ ├── -async-gallery-setting.html │ │ │ ├── get-link-async.html │ │ │ └── index.html │ │ ├── -async-no-member-block │ │ │ ├── -async-no-member-block.html │ │ │ ├── block-async.html │ │ │ └── index.html │ │ ├── -async-notice │ │ │ ├── -async-notice.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-recommend │ │ │ ├── -async-recommend.html │ │ │ ├── index.html │ │ │ └── request-async.html │ │ ├── -async-user-block │ │ │ ├── -async-user-block.html │ │ │ ├── block-async.html │ │ │ ├── get-link-async.html │ │ │ └── index.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.comment │ │ ├── -comment-delete │ │ │ ├── -comment-delete.html │ │ │ ├── -delete-result │ │ │ │ ├── -delete-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── delete.html │ │ │ └── index.html │ │ ├── -comment-read │ │ │ ├── -comment-data │ │ │ │ ├── -comment-data.html │ │ │ │ ├── content.html │ │ │ │ ├── date-time.html │ │ │ │ ├── galler-con.html │ │ │ │ ├── identifier.html │ │ │ │ ├── index.html │ │ │ │ ├── ip-data.html │ │ │ │ ├── is-delete-flag.html │ │ │ │ ├── is-reply.html │ │ │ │ ├── member-icon.html │ │ │ │ ├── name.html │ │ │ │ └── user-id.html │ │ │ ├── -comment-read.html │ │ │ ├── -read-result │ │ │ │ ├── -read-result.html │ │ │ │ ├── comment-list.html │ │ │ │ ├── index.html │ │ │ │ ├── re-page.html │ │ │ │ ├── total-comment.html │ │ │ │ └── total-page.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -comment-write │ │ │ ├── -comment-write.html │ │ │ ├── -write-result │ │ │ │ ├── -write-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── data.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── word.html │ │ │ ├── index.html │ │ │ ├── reply.html │ │ │ └── write.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.dccon │ │ ├── -d-c-con-buy │ │ │ ├── -buy-result │ │ │ │ ├── -buy-result.html │ │ │ │ ├── index.html │ │ │ │ ├── msg.html │ │ │ │ └── result.html │ │ │ ├── -d-c-con-buy.html │ │ │ ├── buy.html │ │ │ └── index.html │ │ ├── -d-c-con-detail │ │ │ ├── -d-c-con-detail.html │ │ │ ├── -d-c-con-info │ │ │ │ ├── -d-c-con-info.html │ │ │ │ ├── description.html │ │ │ │ ├── get-state.html │ │ │ │ ├── index.html │ │ │ │ ├── main-img.html │ │ │ │ ├── mandu.html │ │ │ │ ├── package-index.html │ │ │ │ └── title.html │ │ │ ├── -detail-result │ │ │ │ ├── -detail-result.html │ │ │ │ ├── detail.html │ │ │ │ ├── index.html │ │ │ │ └── info.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -d-c-con-insert │ │ │ ├── -d-c-con-insert.html │ │ │ ├── -insert-result │ │ │ │ ├── -insert-result.html │ │ │ │ ├── alternative-text.html │ │ │ │ ├── image-source.html │ │ │ │ ├── image-tag.html │ │ │ │ ├── index.html │ │ │ │ ├── new-list.html │ │ │ │ └── result.html │ │ │ ├── dc-con.html │ │ │ ├── index.html │ │ │ ├── request.html │ │ │ └── session.html │ │ ├── -d-c-con-list │ │ │ ├── -d-c-con-list.html │ │ │ ├── -list-result │ │ │ │ ├── -list-result.html │ │ │ │ ├── index.html │ │ │ │ ├── list.html │ │ │ │ └── tab.html │ │ │ ├── index.html │ │ │ └── request.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.generic.minigallery │ │ ├── -join-mini-gallery │ │ │ ├── -join-mini-gallery.html │ │ │ ├── -member-join-ok-result │ │ │ │ ├── -member-join-ok-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── status.html │ │ │ ├── -member-join-result │ │ │ │ ├── -member-join-result.html │ │ │ │ ├── index.html │ │ │ │ ├── join-question.html │ │ │ │ └── result.html │ │ │ ├── index.html │ │ │ ├── join.html │ │ │ ├── request-member-join-ok.html │ │ │ └── request-member-join.html │ │ ├── -quit-mini-gallery │ │ │ ├── -member-quit-result │ │ │ │ ├── -member-quit-result.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── -quit-mini-gallery.html │ │ │ ├── index.html │ │ │ └── quit.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.generic.userinfo │ │ ├── -check-joined-mini-gallery │ │ │ ├── -check-joined-mini-gallery.html │ │ │ ├── -check-result │ │ │ │ ├── -check-result.html │ │ │ │ ├── index.html │ │ │ │ ├── my-join-mini-hold.html │ │ │ │ ├── my-join-mini-in.html │ │ │ │ └── my-join-mini-out.html │ │ │ ├── -gallery │ │ │ │ ├── -gallery.html │ │ │ │ ├── hide.html │ │ │ │ ├── id.html │ │ │ │ ├── index.html │ │ │ │ └── title.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -check-managed-gallery │ │ │ ├── -check-managed-gallery.html │ │ │ ├── -check-result │ │ │ │ ├── -check-result.html │ │ │ │ ├── index.html │ │ │ │ └── my-manage-list.html │ │ │ ├── -gallery │ │ │ │ ├── -gallery.html │ │ │ │ ├── hide.html │ │ │ │ ├── id.html │ │ │ │ ├── index.html │ │ │ │ ├── manager-type.html │ │ │ │ ├── title.html │ │ │ │ └── type.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -modify-my-gall │ │ │ ├── -modify-my-gall-result │ │ │ │ ├── -modify-my-gall-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── -modify-my-gall.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -my-gall │ │ │ ├── -my-gall-result │ │ │ │ ├── -my-gall-result.html │ │ │ │ ├── favorite.html │ │ │ │ ├── index.html │ │ │ │ └── my-gall.html │ │ │ ├── -my-gall.html │ │ │ ├── index.html │ │ │ └── request.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.generic │ │ ├── -gallery-ranking │ │ │ ├── -gallery-ranking.html │ │ │ ├── -rank-type │ │ │ │ ├── -d-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -s-t-o-p │ │ │ │ │ └── index.html │ │ │ │ ├── -u-n-k-n-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -u-p │ │ │ │ │ └── index.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── value-of.html │ │ │ │ └── values.html │ │ │ ├── -ranking-item │ │ │ │ ├── -ranking-item.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── gall-link.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── rank-type.html │ │ │ │ ├── rank-updown.html │ │ │ │ └── rank.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -gallery-search │ │ │ ├── -gallery-search-result │ │ │ │ ├── -gallery-search-result.html │ │ │ │ ├── index.html │ │ │ │ ├── main-gallery.html │ │ │ │ ├── main-recommend-gallery.html │ │ │ │ ├── minor-gallery.html │ │ │ │ └── minor-recommend-gallery.html │ │ │ ├── -gallery-search.html │ │ │ ├── index.html │ │ │ └── search.html │ │ ├── -main-page │ │ │ ├── -article │ │ │ │ ├── -article.html │ │ │ │ ├── article-id.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── thumbnail.html │ │ │ │ └── title.html │ │ │ ├── -main-page.html │ │ │ ├── -new-gallery │ │ │ │ ├── -new-gallery.html │ │ │ │ ├── id.html │ │ │ │ ├── index.html │ │ │ │ └── title.html │ │ │ ├── get-best.html │ │ │ ├── get-hit.html │ │ │ ├── get-issue-zoom.html │ │ │ ├── get-new-gallery.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -mini-gallery-ranking │ │ │ ├── -mini-gallery-ranking.html │ │ │ ├── -rank-type │ │ │ │ ├── -d-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -s-t-o-p │ │ │ │ │ └── index.html │ │ │ │ ├── -u-n-k-n-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -u-p │ │ │ │ │ └── index.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── value-of.html │ │ │ │ └── values.html │ │ │ ├── -ranking-item │ │ │ │ ├── -ranking-item.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── gall-link.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── rank-type.html │ │ │ │ ├── rank-updown.html │ │ │ │ └── rank.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -minor-gallery-info │ │ │ ├── -info-result │ │ │ │ ├── -info-result.html │ │ │ │ ├── category-name.html │ │ │ │ ├── create-date.html │ │ │ │ ├── description.html │ │ │ │ ├── hot-state.html │ │ │ │ ├── id.html │ │ │ │ ├── image.html │ │ │ │ ├── index.html │ │ │ │ ├── ko-name.html │ │ │ │ ├── manager.html │ │ │ │ ├── mini.html │ │ │ │ ├── new.html │ │ │ │ ├── sub-manager.html │ │ │ │ └── total-count.html │ │ │ ├── -manager │ │ │ │ ├── -manager.html │ │ │ │ ├── id.html │ │ │ │ ├── index.html │ │ │ │ ├── is-master.html │ │ │ │ └── name.html │ │ │ ├── -mini-gallery-info │ │ │ │ ├── -mini-gallery-info.html │ │ │ │ ├── hide.html │ │ │ │ ├── index.html │ │ │ │ ├── is-member.html │ │ │ │ ├── member-limit.html │ │ │ │ └── total-member.html │ │ │ ├── -minor-gallery-info.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -minor-gallery-ranking │ │ │ ├── -minor-gallery-ranking.html │ │ │ ├── -rank-type │ │ │ │ ├── -d-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -s-t-o-p │ │ │ │ │ └── index.html │ │ │ │ ├── -u-n-k-n-o-w-n │ │ │ │ │ └── index.html │ │ │ │ ├── -u-p │ │ │ │ │ └── index.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── value-of.html │ │ │ │ └── values.html │ │ │ ├── -ranking-item │ │ │ │ ├── -ranking-item.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── gall-link.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── rank-type.html │ │ │ │ ├── rank-updown.html │ │ │ │ └── rank.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -movie-upload │ │ │ ├── -check-result │ │ │ │ ├── -check-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── -movie-upload.html │ │ │ ├── -upload-exception │ │ │ │ ├── -upload-exception.html │ │ │ │ ├── check-result.html │ │ │ │ └── index.html │ │ │ ├── -upload-result │ │ │ │ ├── -upload-result.html │ │ │ │ ├── file-id.html │ │ │ │ ├── height.html │ │ │ │ ├── index.html │ │ │ │ ├── msg.html │ │ │ │ ├── thumbnail-urls.html │ │ │ │ └── width.html │ │ │ ├── check-restriction.html │ │ │ ├── content.html │ │ │ ├── gall-id.html │ │ │ ├── index.html │ │ │ └── upload.html │ │ ├── -total-search │ │ │ ├── -real-time │ │ │ │ ├── -real-time.html │ │ │ │ ├── index.html │ │ │ │ ├── rank.html │ │ │ │ ├── title.html │ │ │ │ └── url.html │ │ │ ├── -searched-article │ │ │ │ ├── -searched-article.html │ │ │ │ ├── article-id.html │ │ │ │ ├── content.html │ │ │ │ ├── gall-id.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── reg-date.html │ │ │ │ └── title.html │ │ │ ├── -total-search-result │ │ │ │ ├── -total-search-result.html │ │ │ │ ├── board.html │ │ │ │ ├── index.html │ │ │ │ ├── main-gallery.html │ │ │ │ ├── minor-gallery.html │ │ │ │ ├── real-time.html │ │ │ │ ├── today-issue.html │ │ │ │ └── wiki.html │ │ │ ├── -total-search.html │ │ │ ├── -wiki │ │ │ │ ├── -wiki.html │ │ │ │ ├── gall-name.html │ │ │ │ ├── index.html │ │ │ │ ├── title.html │ │ │ │ └── url.html │ │ │ ├── index.html │ │ │ └── search.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.management │ │ ├── -change-head-text │ │ │ ├── -change-head-text.html │ │ │ ├── -change-result │ │ │ │ ├── -change-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── state.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -gallery-setting │ │ │ ├── -gallery-setting.html │ │ │ ├── get-link.html │ │ │ ├── get-user-agent.html │ │ │ └── index.html │ │ ├── -no-member-block │ │ │ ├── -block-option │ │ │ │ ├── -block-option.html │ │ │ │ ├── -image-restriction-option │ │ │ │ │ ├── -image-restriction-option.html │ │ │ │ │ ├── index.html │ │ │ │ │ ├── time.html │ │ │ │ │ └── type.html │ │ │ │ ├── cellular.html │ │ │ │ ├── image.html │ │ │ │ ├── index.html │ │ │ │ └── proxy.html │ │ │ ├── -block-result │ │ │ │ ├── -block-result.html │ │ │ │ ├── index.html │ │ │ │ ├── msg.html │ │ │ │ └── result.html │ │ │ ├── -image-status │ │ │ │ ├── -a-n-o-n-y-m-o-u-s │ │ │ │ │ └── index.html │ │ │ │ ├── -c-e-l-l-u-l-a-r │ │ │ │ │ └── index.html │ │ │ │ ├── -n-o-n-e │ │ │ │ │ └── index.html │ │ │ │ ├── -p-r-o-x-y │ │ │ │ │ └── index.html │ │ │ │ ├── -p-r-o-x-y_-a-n-d_-c-e-l-l-u-l-a-r │ │ │ │ │ └── index.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── value-of.html │ │ │ │ ├── value.html │ │ │ │ └── values.html │ │ │ ├── -no-member-block.html │ │ │ ├── block.html │ │ │ └── index.html │ │ ├── -notice │ │ │ ├── -notice-result │ │ │ │ ├── -notice-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── state.html │ │ │ ├── -notice.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -recommend │ │ │ ├── -recommend-result │ │ │ │ ├── -recommend-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ ├── result.html │ │ │ │ └── state.html │ │ │ ├── -recommend.html │ │ │ ├── index.html │ │ │ └── request.html │ │ ├── -user-block │ │ │ ├── -block-category │ │ │ │ ├── -a-d-v-e-r-t-i-s-e-m-e-n-t │ │ │ │ │ └── index.html │ │ │ │ ├── -c-u-s-s_-w-o-r-d-s │ │ │ │ │ └── index.html │ │ │ │ ├── -c-u-s-t-o-m │ │ │ │ │ └── index.html │ │ │ │ ├── -d-e-f-a-m-a-t-i-o-n │ │ │ │ │ └── index.html │ │ │ │ ├── -o-b-s-c-e-n-e │ │ │ │ │ └── index.html │ │ │ │ ├── -p-i-r-a-c-y │ │ │ │ │ └── index.html │ │ │ │ ├── -s-p-a-m-m-i-n-g │ │ │ │ │ └── index.html │ │ │ │ ├── code.html │ │ │ │ ├── entries.html │ │ │ │ ├── index.html │ │ │ │ ├── value-of.html │ │ │ │ └── values.html │ │ │ ├── -block-option │ │ │ │ ├── -block-option.html │ │ │ │ ├── block-category.html │ │ │ │ ├── block-hour.html │ │ │ │ ├── block-reason.html │ │ │ │ ├── comment-id.html │ │ │ │ └── index.html │ │ │ ├── -block-result │ │ │ │ ├── -block-result.html │ │ │ │ ├── cause.html │ │ │ │ ├── index.html │ │ │ │ └── result.html │ │ │ ├── -user-block.html │ │ │ ├── block.html │ │ │ ├── get-link.html │ │ │ ├── get-user-agent.html │ │ │ └── index.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.type.comment │ │ ├── -comment │ │ │ └── index.html │ │ ├── -d-c-con-comment │ │ │ ├── -d-c-con-comment.html │ │ │ ├── dc-con.html │ │ │ └── index.html │ │ ├── -string-comment │ │ │ ├── -string-comment.html │ │ │ ├── index.html │ │ │ └── memo.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.type.content │ │ ├── -content │ │ │ └── index.html │ │ ├── -d-c-con-content │ │ │ ├── -d-c-con-content.html │ │ │ ├── dc-con-insert-result.html │ │ │ ├── dc-con.html │ │ │ └── index.html │ │ ├── -html-content │ │ │ ├── -html-content.html │ │ │ ├── html-string.html │ │ │ └── index.html │ │ ├── -image-content │ │ │ ├── -image-content.html │ │ │ ├── close.html │ │ │ ├── index.html │ │ │ ├── mime-type.html │ │ │ └── stream.html │ │ ├── -markdown-content │ │ │ ├── -markdown-content.html │ │ │ ├── index.html │ │ │ └── markdown-string.html │ │ ├── -movie-content │ │ │ ├── -movie-content.html │ │ │ ├── -movie-info │ │ │ │ ├── -movie-info.html │ │ │ │ ├── allow-download.html │ │ │ │ ├── description.html │ │ │ │ ├── height.html │ │ │ │ ├── index.html │ │ │ │ ├── tag.html │ │ │ │ ├── thumbnail-url.html │ │ │ │ └── width.html │ │ │ ├── close.html │ │ │ ├── index.html │ │ │ ├── info.html │ │ │ ├── mime-type.html │ │ │ └── stream.html │ │ ├── -string-content │ │ │ ├── -string-content.html │ │ │ ├── index.html │ │ │ └── string.html │ │ └── index.html │ ├── be.zvz.kotlininside.api.type │ │ ├── -article │ │ │ ├── -article.html │ │ │ ├── content.html │ │ │ ├── head-text.html │ │ │ ├── index.html │ │ │ └── subject.html │ │ ├── -d-c-con │ │ │ ├── -d-c-con.html │ │ │ ├── detail-index.html │ │ │ ├── img-link.html │ │ │ ├── index.html │ │ │ ├── memo.html │ │ │ ├── package-index.html │ │ │ └── title.html │ │ ├── -gallery │ │ │ ├── -gallery.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── title.html │ │ ├── -head-text │ │ │ ├── -head-text.html │ │ │ ├── identifier.html │ │ │ ├── index.html │ │ │ ├── level.html │ │ │ ├── name.html │ │ │ └── selected.html │ │ └── index.html │ ├── be.zvz.kotlininside.exception │ │ ├── -insufficient-permission-exception │ │ │ ├── -insufficient-permission-exception.html │ │ │ ├── cause-class.html │ │ │ └── index.html │ │ └── index.html │ ├── be.zvz.kotlininside.http │ │ ├── -default-http-client │ │ │ ├── -companion │ │ │ │ ├── -d-e-f-a-u-l-t_-m-i-m-e_-t-y-p-e.html │ │ │ │ └── index.html │ │ │ ├── -default-http-client.html │ │ │ ├── -proxy │ │ │ │ ├── index.html │ │ │ │ ├── ip.html │ │ │ │ └── port.html │ │ │ ├── delete.html │ │ │ ├── get.html │ │ │ ├── head.html │ │ │ ├── index.html │ │ │ ├── patch.html │ │ │ ├── post.html │ │ │ ├── put.html │ │ │ └── upload.html │ │ ├── -http-exception │ │ │ ├── -http-exception.html │ │ │ ├── index.html │ │ │ └── status-code.html │ │ ├── -http-interface │ │ │ ├── -option │ │ │ │ ├── -file-info │ │ │ │ │ ├── -file-info.html │ │ │ │ │ ├── index.html │ │ │ │ │ ├── mime-type.html │ │ │ │ │ └── stream.html │ │ │ │ ├── -option.html │ │ │ │ ├── add-body-parameter.html │ │ │ │ ├── add-header.html │ │ │ │ ├── add-multipart-file-list.html │ │ │ │ ├── add-multipart-file.html │ │ │ │ ├── add-multipart-parameter.html │ │ │ │ ├── add-path-parameter.html │ │ │ │ ├── add-query-parameter.html │ │ │ │ ├── body-parameter.html │ │ │ │ ├── content-type.html │ │ │ │ ├── get-body.html │ │ │ │ ├── headers.html │ │ │ │ ├── index.html │ │ │ │ ├── multipart-content-type.html │ │ │ │ ├── multipart-file-list.html │ │ │ │ ├── multipart-file.html │ │ │ │ ├── multipart-parameter.html │ │ │ │ ├── path-parameter.html │ │ │ │ ├── query-parameter.html │ │ │ │ ├── set-content-type-and-body.html │ │ │ │ └── user-agent.html │ │ │ ├── delete.html │ │ │ ├── get.html │ │ │ ├── head.html │ │ │ ├── index.html │ │ │ ├── patch.html │ │ │ ├── post.html │ │ │ ├── put.html │ │ │ └── upload.html │ │ ├── -request │ │ │ ├── get-default-option.html │ │ │ ├── index.html │ │ │ └── redirect-url.html │ │ └── index.html │ ├── be.zvz.kotlininside.json │ │ ├── -json-browser │ │ │ ├── --index--.html │ │ │ ├── -n-u-l-l_-b-r-o-w-s-e-r.html │ │ │ ├── as-boolean.html │ │ │ ├── as-integer.html │ │ │ ├── as-long.html │ │ │ ├── as-nullable-boolean.html │ │ │ ├── as-nullable-integer.html │ │ │ ├── as-nullable-long.html │ │ │ ├── as.html │ │ │ ├── create.html │ │ │ ├── format.html │ │ │ ├── get.html │ │ │ ├── index.html │ │ │ ├── is-list.html │ │ │ ├── is-map.html │ │ │ ├── is-null.html │ │ │ ├── mapper.html │ │ │ ├── parse.html │ │ │ ├── put.html │ │ │ ├── safe-text.html │ │ │ ├── stringify.html │ │ │ ├── text.html │ │ │ ├── to-map.html │ │ │ ├── to-string.html │ │ │ └── values.html │ │ └── index.html │ ├── be.zvz.kotlininside.migbase64 │ │ ├── -base64-i-o │ │ │ ├── -base64-i-o.html │ │ │ ├── encode.html │ │ │ └── index.html │ │ ├── -base64 │ │ │ ├── -base64.html │ │ │ ├── decode-fast.html │ │ │ ├── decode.html │ │ │ ├── encode-to-byte.html │ │ │ ├── encode-to-char.html │ │ │ ├── encode-to-string.html │ │ │ └── index.html │ │ └── index.html │ ├── be.zvz.kotlininside.security │ │ ├── -app │ │ │ ├── -app.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── token.html │ │ ├── -auth │ │ │ ├── -app-check │ │ │ │ ├── -app-check.html │ │ │ │ ├── date.html │ │ │ │ ├── index.html │ │ │ │ ├── notice-update.html │ │ │ │ ├── notice.html │ │ │ │ ├── result.html │ │ │ │ └── version.html │ │ │ ├── -auth.html │ │ │ ├── fcm-token.html │ │ │ ├── fetch-android-checkin.html │ │ │ ├── fetch-app-id.html │ │ │ ├── fetch-fcm-token.html │ │ │ ├── fid.html │ │ │ ├── generate-aid-login-from-checkin.html │ │ │ ├── generate-hashed-app-key.html │ │ │ ├── get-app-check.html │ │ │ ├── get-app-id.html │ │ │ ├── index.html │ │ │ ├── login.html │ │ │ └── refresh-token.html │ │ └── index.html │ ├── be.zvz.kotlininside.session.user.named │ │ ├── -duplicate-named │ │ │ ├── -duplicate-named.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── password.html │ │ ├── -named │ │ │ ├── -named.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── password.html │ │ └── index.html │ ├── be.zvz.kotlininside.session.user │ │ ├── -anonymous │ │ │ ├── -anonymous.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── password.html │ │ ├── -login-user │ │ │ ├── -login-user.html │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── password.html │ │ ├── -user-type │ │ │ ├── -a-n-o-n-y-m-o-u-s │ │ │ │ └── index.html │ │ │ ├── -d-u-p-l-i-c-a-t-e_-n-a-m-e-d │ │ │ │ └── index.html │ │ │ ├── -n-a-m-e-d │ │ │ │ └── index.html │ │ │ ├── entries.html │ │ │ ├── index.html │ │ │ ├── session-type.html │ │ │ ├── value-of.html │ │ │ └── values.html │ │ ├── -user │ │ │ ├── id.html │ │ │ ├── index.html │ │ │ └── password.html │ │ └── index.html │ ├── be.zvz.kotlininside.session │ │ ├── -session-detail │ │ │ ├── -session-detail.html │ │ │ ├── auth-change.html │ │ │ ├── cause.html │ │ │ ├── index.html │ │ │ ├── is-adult.html │ │ │ ├── is-dormancy.html │ │ │ ├── is-gonick.html │ │ │ ├── is-otp.html │ │ │ ├── is-security-code.html │ │ │ ├── mail-send.html │ │ │ ├── name.html │ │ │ ├── pw-campaign.html │ │ │ ├── result.html │ │ │ ├── session-type.html │ │ │ ├── user-id.html │ │ │ └── user-no.html │ │ ├── -session │ │ │ ├── -session.html │ │ │ ├── detail.html │ │ │ ├── index.html │ │ │ └── user.html │ │ └── index.html │ ├── be.zvz.kotlininside.utils │ │ ├── -string-util │ │ │ ├── index.html │ │ │ ├── md-to-html.html │ │ │ ├── ok-to-boolean.html │ │ │ ├── to-html.html │ │ │ └── yn-to-boolean.html │ │ └── index.html │ ├── be.zvz.kotlininside.value │ │ ├── -api-url │ │ │ ├── -a-p-p_-a-p-i.html │ │ │ ├── -a-u-t-h_-a-p-i.html │ │ │ ├── -article │ │ │ │ ├── -d-e-l-e-t-e.html │ │ │ │ ├── -d-o-w-n-v-o-t-e.html │ │ │ │ ├── -h-i-t_-u-p-v-o-t-e.html │ │ │ │ ├── -i-n-s-e-r-t_-m-o-v-i-e_-i-n-f-o.html │ │ │ │ ├── -l-i-s-t.html │ │ │ │ ├── -m-o-d-i-f-y.html │ │ │ │ ├── -r-e-a-d.html │ │ │ │ ├── -r-e-p-o-r-t.html │ │ │ │ ├── -u-p-v-o-t-e.html │ │ │ │ ├── -w-r-i-t-e.html │ │ │ │ └── index.html │ │ │ ├── -auth │ │ │ │ ├── -a-p-p_-c-h-e-c-k.html │ │ │ │ ├── -a-p-p_-i-d.html │ │ │ │ ├── -l-o-g-i-n.html │ │ │ │ └── index.html │ │ │ ├── -comment │ │ │ │ ├── -d-e-l-e-t-e.html │ │ │ │ ├── -o-k.html │ │ │ │ ├── -r-e-a-d.html │ │ │ │ └── index.html │ │ │ ├── -d-c-con │ │ │ │ ├── -d-c-c-o-n.html │ │ │ │ └── index.html │ │ │ ├── -firebase │ │ │ │ ├── -i-n-s-t-a-l-l-a-t-i-o-n-s.html │ │ │ │ ├── -r-e-m-o-t-e_-c-o-n-f-i-g.html │ │ │ │ └── index.html │ │ │ ├── -gallery │ │ │ │ ├── -m-i-n-o-r_-b-l-o-c-k_-a-d-d.html │ │ │ │ ├── -m-i-n-o-r_-b-l-o-c-k_-w-e-b.html │ │ │ │ ├── -m-i-n-o-r_-i-n-f-o.html │ │ │ │ ├── -m-i-n-o-r_-m-a-n-a-g-e-m-e-n-t.html │ │ │ │ ├── -m-i-n-o-r_-m-a-n-a-g-e-r_-r-e-q-u-e-s-t.html │ │ │ │ ├── -m-i-n-o-r_-n-o-m-e-m-b-e-r.html │ │ │ │ └── index.html │ │ │ ├── -m-a-i-n_-a-p-i.html │ │ │ ├── -m-o-b-i-l-e_-a-p-p.html │ │ │ ├── -m-o-b-i-l-e_-w-e-b.html │ │ │ ├── -m-o-b-i-l-e_-w-e-b_-h-t-t-p-s.html │ │ │ ├── -m-o-v-i-e_-u-p-l-o-a-d.html │ │ │ ├── -main-info │ │ │ │ ├── -a-p-p_-m-a-i-n.html │ │ │ │ ├── -g-a-l-l-e-r-y_-r-a-n-k-i-n-g.html │ │ │ │ ├── -m-i-n-i_-g-a-l-l-e-r-y_-r-a-n-k-i-n-g.html │ │ │ │ ├── -m-i-n-o-r_-g-a-l-l-e-r-y_-r-a-n-k-i-n-g.html │ │ │ │ ├── -n-o-t-i-c-e.html │ │ │ │ └── index.html │ │ │ ├── -mini-gallery │ │ │ │ ├── -j-o-i-n.html │ │ │ │ ├── -j-o-i-n_-o-k.html │ │ │ │ ├── -q-u-i-t.html │ │ │ │ └── index.html │ │ │ ├── -p-c_-w-e-b.html │ │ │ ├── -play-service │ │ │ │ ├── -a-n-d-r-o-i-d_-c-l-i-e-n-t.html │ │ │ │ ├── -c-h-e-c-k-i-n.html │ │ │ │ ├── -r-e-g-i-s-t-e-r3.html │ │ │ │ └── index.html │ │ │ ├── -r-e-d-i-r-e-c-t.html │ │ │ ├── -search │ │ │ │ ├── -s-e-a-r-c-h.html │ │ │ │ └── index.html │ │ │ ├── -u-p-l-o-a-d.html │ │ │ ├── -upload │ │ │ │ ├── -c-h-e-c-k_-u-p-l-o-a-d_-r-e-s-t-r-i-c-t-i-o-n.html │ │ │ │ ├── -m-o-v-i-e.html │ │ │ │ └── index.html │ │ │ ├── -user │ │ │ │ ├── -m-y_-g-a-l-l.html │ │ │ │ ├── -m-y_-g-a-l-l_-m-o-d-i-f-y.html │ │ │ │ ├── -m-y_-m-a-n-a-g-e_-g-a-l-l_-c-h-e-c-k.html │ │ │ │ ├── -m-y_-m-i-n-i_-j-o-i-n_-c-h-e-c-k.html │ │ │ │ └── index.html │ │ │ └── index.html │ │ ├── -const │ │ │ ├── -d-c_-a-p-p_-p-a-c-k-a-g-e.html │ │ │ ├── -d-c_-a-p-p_-s-i-g-n-a-t-u-r-e.html │ │ │ ├── -d-c_-a-p-p_-t-a-r-g-e-t_-v-e-r-s-i-o-n.html │ │ │ ├── -d-c_-a-p-p_-v-e-r-s-i-o-n_-c-o-d-e.html │ │ │ ├── -d-c_-a-p-p_-v-e-r-s-i-o-n_-n-a-m-e.html │ │ │ ├── -firebase │ │ │ │ ├── -a-p-p_-i-d.html │ │ │ │ ├── -a-u-t-h_-v-e-r-s-i-o-n.html │ │ │ │ ├── -c-e-r-t.html │ │ │ │ ├── -c-l-i-v.html │ │ │ │ ├── -f-i-r-e-b-a-s-e_-c-l-i-e-n-t.html │ │ │ │ ├── -g-c-m_-v-e-r-s-i-o-n.html │ │ │ │ ├── -i-n-f-o.html │ │ │ │ ├── -o-s_-v-e-r-s-i-o-n.html │ │ │ │ ├── -r-e-m-o-t-e_-c-o-n-f-i-g_-s-d-k_-v-e-r-s-i-o-n.html │ │ │ │ ├── -s-d-k_-v-e-r-s-i-o-n.html │ │ │ │ ├── -t-a-r-g-e-t_-v-e-r.html │ │ │ │ └── index.html │ │ │ ├── -installations │ │ │ │ ├── -x_-a-n-d-r-o-i-d_-c-e-r-t.html │ │ │ │ ├── -x_-a-n-d-r-o-i-d_-p-a-c-k-a-g-e.html │ │ │ │ ├── -x_-g-o-o-g_-a-p-i_-k-e-y.html │ │ │ │ └── index.html │ │ │ ├── -register3 │ │ │ │ ├── -a-p-p.html │ │ │ │ ├── -c-e-r-t.html │ │ │ │ ├── -g-c-m_-v-e-r-s-i-o-n.html │ │ │ │ ├── -s-e-n-d-e-r.html │ │ │ │ ├── -u-s-e-r_-a-g-e-n-t.html │ │ │ │ ├── -x_-f-i-r-e-b-a-s-e_-a-p-p_-n-a-m-e_-h-a-s-h.html │ │ │ │ ├── -x_-s-c-o-p-e_-a-l-l.html │ │ │ │ ├── -x_-s-c-o-p-e_-r-e-f-r-e-s-h_-r-e-m-o-t-e_-c-o-n-f-i-g.html │ │ │ │ ├── -x_-s-c-o-p-e_-s-h-o-w_-n-o-t-i-c-e_-m-e-s-s-a-g-e.html │ │ │ │ └── index.html │ │ │ ├── -u-s-e-r_-a-g-e-n-t.html │ │ │ └── index.html │ │ └── index.html │ ├── be.zvz.kotlininside │ │ ├── -kotlin-inside │ │ │ ├── -companion │ │ │ │ ├── create-instance.html │ │ │ │ ├── get-instance.html │ │ │ │ └── index.html │ │ │ ├── app.html │ │ │ ├── auth.html │ │ │ ├── hashed-app-key.html │ │ │ ├── http-interface.html │ │ │ ├── index.html │ │ │ ├── session.html │ │ │ └── user.html │ │ └── index.html │ └── package-list ├── images │ ├── anchor-copy-button.svg │ ├── arrow_down.svg │ ├── burger.svg │ ├── copy-icon.svg │ ├── copy-successful-icon.svg │ ├── footer-go-to-link.svg │ ├── go-to-top-icon.svg │ ├── logo-icon.svg │ ├── nav-icons │ │ ├── abstract-class-kotlin.svg │ │ ├── abstract-class.svg │ │ ├── annotation-kotlin.svg │ │ ├── annotation.svg │ │ ├── class-kotlin.svg │ │ ├── class.svg │ │ ├── enum-kotlin.svg │ │ ├── enum.svg │ │ ├── exception-class.svg │ │ ├── field-value.svg │ │ ├── field-variable.svg │ │ ├── function.svg │ │ ├── interface-kotlin.svg │ │ ├── interface.svg │ │ ├── object.svg │ │ └── typealias-kotlin.svg │ └── theme-toggle.svg ├── index.html ├── navigation.html ├── scripts │ ├── clipboard.js │ ├── main.js │ ├── navigation-loader.js │ ├── pages.json │ ├── platform-content-handler.js │ ├── prism.js │ ├── sourceset_dependencies.js │ └── symbol-parameters-wrapper_deferred.js └── styles │ ├── font-jb-sans-auto.css │ ├── jetbrains-mono.css │ ├── logo-styles.css │ ├── main.css │ ├── prism.css │ └── style.css ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── src ├── main │ ├── java │ │ └── be │ │ │ └── zvz │ │ │ └── kotlininside │ │ │ ├── http │ │ │ └── HttpInterface.java │ │ │ ├── json │ │ │ └── JsonBrowser.java │ │ │ └── migbase64 │ │ │ ├── Base64.java │ │ │ ├── Base64IO.java │ │ │ └── Dictionary.java │ ├── kotlin │ │ └── be │ │ │ └── zvz │ │ │ └── kotlininside │ │ │ ├── KotlinInside.kt │ │ │ ├── api │ │ │ ├── article │ │ │ │ ├── ArticleDelete.kt │ │ │ │ ├── ArticleHitUpvote.kt │ │ │ │ ├── ArticleList.kt │ │ │ │ ├── ArticleModify.kt │ │ │ │ ├── ArticleRead.kt │ │ │ │ ├── ArticleReport.kt │ │ │ │ ├── ArticleVote.kt │ │ │ │ └── ArticleWrite.kt │ │ │ ├── async │ │ │ │ ├── article │ │ │ │ │ ├── AsyncArticleDelete.kt │ │ │ │ │ ├── AsyncArticleHitUpvote.kt │ │ │ │ │ ├── AsyncArticleList.kt │ │ │ │ │ ├── AsyncArticleModify.kt │ │ │ │ │ ├── AsyncArticleRead.kt │ │ │ │ │ ├── AsyncArticleReport.kt │ │ │ │ │ ├── AsyncArticleVote.kt │ │ │ │ │ └── AsyncArticleWrite.kt │ │ │ │ ├── comment │ │ │ │ │ ├── AsyncCommentDelete.kt │ │ │ │ │ ├── AsyncCommentRead.kt │ │ │ │ │ └── AsyncCommentWrite.kt │ │ │ │ ├── dccon │ │ │ │ │ ├── AsyncDCConBuy.kt │ │ │ │ │ ├── AsyncDCConDetail.kt │ │ │ │ │ └── AsyncDCConList.kt │ │ │ │ ├── generic │ │ │ │ │ ├── AsyncGalleryRanking.kt │ │ │ │ │ ├── AsyncGallerySearch.kt │ │ │ │ │ ├── AsyncMainPage.kt │ │ │ │ │ ├── AsyncMiniGalleryRanking.kt │ │ │ │ │ ├── AsyncMinorGalleryInfo.kt │ │ │ │ │ ├── AsyncMinorGalleryRanking.kt │ │ │ │ │ ├── AsyncTotalSearch.kt │ │ │ │ │ ├── minigallery │ │ │ │ │ │ ├── AsyncJoinMiniGallery.kt │ │ │ │ │ │ └── AsyncQuitMiniGallery.kt │ │ │ │ │ └── userinfo │ │ │ │ │ │ ├── AsyncCheckJoinedMiniGallery.kt │ │ │ │ │ │ ├── AsyncCheckManagedGallery.kt │ │ │ │ │ │ ├── AsyncModifyMyGall.kt │ │ │ │ │ │ └── AsyncMyGall.kt │ │ │ │ └── management │ │ │ │ │ ├── AsyncChangeHeadText.kt │ │ │ │ │ ├── AsyncGallerySetting.kt │ │ │ │ │ ├── AsyncNoMemberBlock.kt │ │ │ │ │ ├── AsyncNotice.kt │ │ │ │ │ ├── AsyncRecommend.kt │ │ │ │ │ └── AsyncUserBlock.kt │ │ │ ├── comment │ │ │ │ ├── CommentDelete.kt │ │ │ │ ├── CommentRead.kt │ │ │ │ └── CommentWrite.kt │ │ │ ├── dccon │ │ │ │ ├── DCConBuy.kt │ │ │ │ ├── DCConDetail.kt │ │ │ │ ├── DCConInsert.kt │ │ │ │ └── DCConList.kt │ │ │ ├── generic │ │ │ │ ├── GalleryRanking.kt │ │ │ │ ├── GallerySearch.kt │ │ │ │ ├── MainPage.kt │ │ │ │ ├── MiniGalleryRanking.kt │ │ │ │ ├── MinorGalleryInfo.kt │ │ │ │ ├── MinorGalleryRanking.kt │ │ │ │ ├── MovieUpload.kt │ │ │ │ ├── TotalSearch.kt │ │ │ │ ├── minigallery │ │ │ │ │ ├── JoinMiniGallery.kt │ │ │ │ │ └── QuitMiniGallery.kt │ │ │ │ └── userinfo │ │ │ │ │ ├── CheckJoinedMiniGallery.kt │ │ │ │ │ ├── CheckManagedGallery.kt │ │ │ │ │ ├── ModifyMyGall.kt │ │ │ │ │ └── MyGall.kt │ │ │ ├── management │ │ │ │ ├── ChangeHeadText.kt │ │ │ │ ├── GallerySetting.kt │ │ │ │ ├── NoMemberBlock.kt │ │ │ │ ├── Notice.kt │ │ │ │ ├── Recommend.kt │ │ │ │ └── UserBlock.kt │ │ │ └── type │ │ │ │ ├── Article.kt │ │ │ │ ├── DCCon.kt │ │ │ │ ├── Gallery.kt │ │ │ │ ├── HeadText.kt │ │ │ │ ├── comment │ │ │ │ ├── Comment.kt │ │ │ │ ├── DCConComment.kt │ │ │ │ └── StringComment.kt │ │ │ │ └── content │ │ │ │ ├── Content.kt │ │ │ │ ├── DCConContent.kt │ │ │ │ ├── HtmlContent.kt │ │ │ │ ├── ImageContent.kt │ │ │ │ ├── MarkdownContent.kt │ │ │ │ ├── MovieContent.kt │ │ │ │ └── StringContent.kt │ │ │ ├── exception │ │ │ └── InsufficientPermissionException.kt │ │ │ ├── http │ │ │ ├── DefaultHttpClient.kt │ │ │ ├── HttpException.kt │ │ │ └── Request.kt │ │ │ ├── security │ │ │ ├── App.kt │ │ │ ├── Auth.kt │ │ │ └── RandomFidGenerator.kt │ │ │ ├── session │ │ │ ├── Session.kt │ │ │ ├── SessionDetail.kt │ │ │ └── user │ │ │ │ ├── Anonymous.kt │ │ │ │ ├── LoginUser.kt │ │ │ │ ├── User.kt │ │ │ │ ├── UserType.kt │ │ │ │ └── named │ │ │ │ ├── DuplicateNamed.kt │ │ │ │ └── Named.kt │ │ │ ├── utils │ │ │ └── StringUtil.kt │ │ │ └── value │ │ │ ├── ApiUrl.kt │ │ │ └── Const.kt │ └── proto │ │ └── checkin.proto └── test │ └── kotlin │ └── be │ └── zvz │ └── kotlininside │ └── KotlinInsideTest.kt └── 구현 TODO.md /.editorconfig: -------------------------------------------------------------------------------- 1 | [*{kt,kts}] 2 | disabled_rules = no-wildcard-imports 3 | max_line_length = 130 4 | ij_kotlin_allow_trailing_comma_on_call_site = false 5 | ij_kotlin_allow_trailing_comma = false -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 2 * * 0' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | # Override automatic language detection by changing the below list 21 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] 22 | language: ['java'] 23 | # Learn more... 24 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 25 | 26 | steps: 27 | - name: Checkout repository 28 | uses: actions/checkout@v2 29 | with: 30 | # We must fetch at least the immediate parents so that if this is 31 | # a pull request then we can checkout the head. 32 | fetch-depth: 2 33 | 34 | # If this run was triggered by a pull request event, then checkout 35 | # the head of the pull request instead of the merge commit. 36 | - run: git checkout HEAD^2 37 | if: ${{ github.event_name == 'pull_request' }} 38 | 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v2 42 | with: 43 | languages: ${{ matrix.language }} 44 | # If you wish to specify custom queries, you can do so here or in a config file. 45 | # By default, queries listed here will override any specified in a config file. 46 | # Prefix the list here with "+" to use these queries and those in the config file. 47 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 48 | 49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 50 | # If this step fails, then you should remove it and run the build manually (see below) 51 | - name: Autobuild 52 | uses: github/codeql-action/autobuild@v2 53 | 54 | # ℹ️ Command-line programs to run using the OS shell. 55 | # 📚 https://git.io/JvXDl 56 | 57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 58 | # and modify them (or add more) to build your code if your project 59 | # uses a compiled language 60 | 61 | #- run: | 62 | # make bootstrap 63 | # make release 64 | 65 | - name: Perform CodeQL Analysis 66 | uses: github/codeql-action/analyze@v2 67 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | - '!dependabot**' 8 | - '!dev' 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | java: [ '17', '8' ] 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - name: Set up JDK ${{ matrix.java }} 21 | uses: actions/setup-java@v1 22 | with: 23 | java-version: ${{ matrix.java }} 24 | - name: Test with Gradle 25 | run: ./gradlew test -i 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | 7 | local.properties 8 | /gradle.properties 9 | .idea 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: java 3 | jdk: 4 | - openjdk8 5 | - openjdk9 6 | - openjdk11 7 | - oraclejdk11 8 | 9 | 10 | sudo: false 11 | 12 | addons: 13 | apt: 14 | packages: 15 | - tree 16 | 17 | # https://docs.travis-ci.com/user/customizing-the-build#Skipping-the-Installation-Step 18 | install: true # if we don't skip install, ./gradlew assemble is invoked, but this task is not available. 19 | 20 | script: 21 | - ./gradlew test -i 22 | 23 | # configure caching (https://docs.travis-ci.com/user/languages/java/#Caching) 24 | before_cache: 25 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 26 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 27 | # format from https://docs.travis-ci.com/user/caching/#Enabling-multiple-caching-features 28 | cache: 29 | bundler: true 30 | directories: 31 | - $HOME/.gradle/caches/ 32 | - $HOME/.gradle/wrapper/ 33 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside.api.generic/-main-page/-main-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MainPage 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

MainPage

68 |
69 |
constructor()
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside.migbase64/-base64-i-o/-base64-i-o.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Base64IO 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

Base64IO

68 |
69 |
constructor()
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside.migbase64/-base64/-base64.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Base64 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

Base64

68 |
69 |
constructor()
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside.security/-app/id.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | id 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

id

68 |
69 |
val id: String
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside.security/-auth/-auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Auth 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

Auth

68 |
69 |
constructor()
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside/-kotlin-inside/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | app 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

app

68 |
69 |
lateinit var app: App
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside/-kotlin-inside/auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | auth 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

auth

68 |
69 |
val auth: Auth
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/-kotlin-inside/be.zvz.kotlininside/-kotlin-inside/user.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | user 6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 59 |
60 | 63 |
64 |
65 | 66 |
67 |

user

68 |
69 |
val user: User
70 |
71 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/images/anchor-copy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/images/burger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/images/copy-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/images/copy-successful-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/images/footer-go-to-link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/images/go-to-top-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/images/logo-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/abstract-class-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/images/nav-icons/abstract-class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/images/nav-icons/annotation-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/annotation.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/class-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/enum-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/enum.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/exception-class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/field-value.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/images/nav-icons/field-variable.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/images/nav-icons/function.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/interface-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/interface.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/images/nav-icons/object.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/nav-icons/typealias-kotlin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/images/theme-toggle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /docs/scripts/clipboard.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | document.querySelectorAll('span.copy-icon').forEach(element => { 3 | element.addEventListener('click', (el) => copyElementsContentToClipboard(element)); 4 | }) 5 | 6 | document.querySelectorAll('span.anchor-icon').forEach(element => { 7 | element.addEventListener('click', (el) => { 8 | if(element.hasAttribute('pointing-to')){ 9 | const location = hrefWithoutCurrentlyUsedAnchor() + '#' + element.getAttribute('pointing-to') 10 | copyTextToClipboard(element, location) 11 | } 12 | }); 13 | }) 14 | }) 15 | 16 | const copyElementsContentToClipboard = (element) => { 17 | const selection = window.getSelection(); 18 | const range = document.createRange(); 19 | range.selectNodeContents(element.parentNode.parentNode); 20 | selection.removeAllRanges(); 21 | selection.addRange(range); 22 | 23 | copyAndShowPopup(element, () => selection.removeAllRanges()) 24 | } 25 | 26 | const copyTextToClipboard = (element, text) => { 27 | var textarea = document.createElement("textarea"); 28 | textarea.textContent = text; 29 | textarea.style.position = "fixed"; 30 | document.body.appendChild(textarea); 31 | textarea.select(); 32 | 33 | copyAndShowPopup(element, () => document.body.removeChild(textarea)) 34 | } 35 | 36 | const copyAndShowPopup = (element, after) => { 37 | try { 38 | document.execCommand('copy'); 39 | element.nextElementSibling.classList.add('active-popup'); 40 | setTimeout(() => { 41 | element.nextElementSibling.classList.remove('active-popup'); 42 | }, 1200); 43 | } catch (e) { 44 | console.error('Failed to write to clipboard:', e) 45 | } 46 | finally { 47 | if(after) after() 48 | } 49 | } 50 | 51 | const hrefWithoutCurrentlyUsedAnchor = () => window.location.href.split('#')[0] 52 | 53 | -------------------------------------------------------------------------------- /docs/scripts/navigation-loader.js: -------------------------------------------------------------------------------- 1 | navigationPageText = fetch(pathToRoot + "navigation.html").then(response => response.text()) 2 | 3 | displayNavigationFromPage = () => { 4 | navigationPageText.then(data => { 5 | document.getElementById("sideMenu").innerHTML = data; 6 | }).then(() => { 7 | document.querySelectorAll(".overview > a").forEach(link => { 8 | link.setAttribute("href", pathToRoot + link.getAttribute("href")); 9 | }) 10 | }).then(() => { 11 | document.querySelectorAll(".sideMenuPart").forEach(nav => { 12 | if (!nav.classList.contains("hidden")) 13 | nav.classList.add("hidden") 14 | }) 15 | }).then(() => { 16 | revealNavigationForCurrentPage() 17 | }).then(() => { 18 | scrollNavigationToSelectedElement() 19 | }) 20 | document.querySelectorAll('.footer a[href^="#"]').forEach(anchor => { 21 | anchor.addEventListener('click', function (e) { 22 | e.preventDefault(); 23 | document.querySelector(this.getAttribute('href')).scrollIntoView({ 24 | behavior: 'smooth' 25 | }); 26 | }); 27 | }); 28 | } 29 | 30 | revealNavigationForCurrentPage = () => { 31 | let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); 32 | let parts = document.querySelectorAll(".sideMenuPart"); 33 | let found = 0; 34 | do { 35 | parts.forEach(part => { 36 | if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { 37 | found = 1; 38 | if (part.classList.contains("hidden")) { 39 | part.classList.remove("hidden"); 40 | part.setAttribute('data-active', ""); 41 | } 42 | revealParents(part) 43 | } 44 | }); 45 | pageId = pageId.substring(0, pageId.lastIndexOf("/")) 46 | } while (pageId.indexOf("/") !== -1 && found === 0) 47 | }; 48 | revealParents = (part) => { 49 | if (part.classList.contains("sideMenuPart")) { 50 | if (part.classList.contains("hidden")) 51 | part.classList.remove("hidden"); 52 | revealParents(part.parentNode) 53 | } 54 | }; 55 | 56 | scrollNavigationToSelectedElement = () => { 57 | let selectedElement = document.querySelector('div.sideMenuPart[data-active]') 58 | if (selectedElement == null) { // nothing selected, probably just the main page opened 59 | return 60 | } 61 | 62 | let hasIcon = selectedElement.querySelectorAll(":scope > div.overview span.nav-icon").length > 0 63 | 64 | // for instance enums also have children and are expandable, but are not package/module elements 65 | let isPackageElement = selectedElement.children.length > 1 && !hasIcon 66 | if (isPackageElement) { 67 | // if package is selected or linked, it makes sense to align it to top 68 | // so that you can see all the members it contains 69 | selectedElement.scrollIntoView(true) 70 | } else { 71 | // if a member within a package is linked, it makes sense to center it since it, 72 | // this should make it easier to look at surrounding members 73 | selectedElement.scrollIntoView({ 74 | behavior: 'auto', 75 | block: 'center', 76 | inline: 'center' 77 | }) 78 | } 79 | } 80 | 81 | /* 82 | This is a work-around for safari being IE of our times. 83 | It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it 84 | */ 85 | if (document.readyState == 'loading') { 86 | window.addEventListener('DOMContentLoaded', () => { 87 | displayNavigationFromPage() 88 | }) 89 | } else { 90 | displayNavigationFromPage() 91 | } 92 | -------------------------------------------------------------------------------- /docs/scripts/sourceset_dependencies.js: -------------------------------------------------------------------------------- 1 | sourceset_dependencies='{":dokkaHtml/main":[]}' 2 | -------------------------------------------------------------------------------- /docs/scripts/symbol-parameters-wrapper_deferred.js: -------------------------------------------------------------------------------- 1 | // helps with some corner cases where starts working already, 2 | // but the signature is not yet long enough to be wrapped 3 | const leftPaddingPx = 60 4 | 5 | const symbolResizeObserver = new ResizeObserver(entries => { 6 | entries.forEach(entry => { 7 | const symbolElement = entry.target 8 | symbolResizeObserver.unobserve(symbolElement) // only need it once, otherwise will be executed multiple times 9 | wrapSymbolParameters(symbolElement); 10 | }) 11 | }); 12 | 13 | const wrapAllSymbolParameters = () => { 14 | document.querySelectorAll("div.symbol").forEach(symbol => wrapSymbolParameters(symbol)) 15 | } 16 | 17 | const wrapSymbolParameters = (symbol) => { 18 | let parametersBlock = symbol.querySelector("span.parameters") 19 | if (parametersBlock == null) { 20 | return // nothing to wrap 21 | } 22 | 23 | let symbolBlockWidth = symbol.clientWidth 24 | 25 | // Even though the script is marked as `defer` and we wait for `DOMContentLoaded` event, 26 | // it can happen that `symbolBlockWidth` is 0, indicating that something hasn't been loaded. 27 | // In this case, just retry once all styles have been applied and it has been resized correctly. 28 | if (symbolBlockWidth === 0) { 29 | symbolResizeObserver.observe(symbol) 30 | return 31 | } 32 | 33 | let innerTextWidth = Array.from(symbol.children) 34 | .filter(it => !it.classList.contains("block")) // blocks are usually on their own (like annotations), so ignore it 35 | .map(it => it.getBoundingClientRect().width).reduce((a, b) => a + b, 0) 36 | 37 | // if signature text takes up more than a single line, wrap params for readability 38 | let shouldWrapParams = innerTextWidth > (symbolBlockWidth - leftPaddingPx) 39 | if (shouldWrapParams) { 40 | parametersBlock.classList.add("wrapped") 41 | parametersBlock.querySelectorAll("span.parameter").forEach(param => { 42 | // has to be a physical indent so that it can be copied. styles like 43 | // paddings and `::before { content: " " }` do not work for that 44 | param.prepend(createNbspIndent()) 45 | }) 46 | } 47 | } 48 | 49 | const createNbspIndent = () => { 50 | let indent = document.createElement("span") 51 | indent.append(document.createTextNode("\u00A0\u00A0\u00A0\u00A0")) 52 | indent.classList.add("nbsp-indent") 53 | return indent 54 | } 55 | 56 | const resetAllSymbolParametersWrapping = () => { 57 | document.querySelectorAll("div.symbol").forEach(symbol => resetSymbolParametersWrapping(symbol)) 58 | } 59 | 60 | const resetSymbolParametersWrapping = (symbol) => { 61 | let parameters = symbol.querySelector("span.parameters") 62 | if (parameters != null) { 63 | parameters.classList.remove("wrapped") 64 | parameters.querySelectorAll("span.parameter").forEach(param => { 65 | let indent = param.querySelector("span.nbsp-indent") 66 | if (indent != null) indent.remove() 67 | }) 68 | } 69 | } 70 | 71 | if (document.readyState === 'loading') { 72 | window.addEventListener('DOMContentLoaded', () => { 73 | wrapAllSymbolParameters() 74 | }) 75 | } else { 76 | wrapAllSymbolParameters() 77 | } 78 | 79 | window.onresize = event => { 80 | // need to re-calculate if params need to be wrapped after resize 81 | resetAllSymbolParametersWrapping() 82 | wrapAllSymbolParameters() 83 | } 84 | -------------------------------------------------------------------------------- /docs/styles/font-jb-sans-auto.css: -------------------------------------------------------------------------------- 1 | /* Light weight */ 2 | @font-face { 3 | font-family: 'JetBrains Sans'; 4 | src: url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-Light.woff2') format('woff2'), url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-Light.woff') format('woff'); 5 | font-weight: 300; 6 | font-style: normal; 7 | } 8 | /* Regular weight */ 9 | @font-face { 10 | font-family: 'JetBrains Sans'; 11 | src: url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-Regular.woff2') format('woff2'), url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-Regular.woff') format('woff'); 12 | font-weight: 400; 13 | font-style: normal; 14 | } 15 | /* SemiBold weight */ 16 | @font-face { 17 | font-family: 'JetBrains Sans'; 18 | src: url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-SemiBold.woff2') format('woff2'), url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans-SemiBold.woff') format('woff'); 19 | font-weight: 600; 20 | font-style: normal; 21 | } 22 | 23 | @supports (font-variation-settings: normal) { 24 | @font-face { 25 | font-family: 'JetBrains Sans'; 26 | src: url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans.woff2') format('woff2 supports variations'), 27 | url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans.woff2') format('woff2-variations'), 28 | url('https://resources.jetbrains.com/storage/jetbrains-sans/JetBrainsSans.woff') format('woff-variations'); 29 | font-weight: 100 900; 30 | font-style: normal; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /docs/styles/jetbrains-mono.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'JetBrains Mono'; 3 | src: url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/web/JetBrainsMono-Regular.eot') format('embedded-opentype'), 4 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/webfonts/JetBrainsMono-Regular.woff2') format('woff2'), 5 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/ttf/JetBrainsMono-Regular.ttf') format('truetype'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | @font-face{ 11 | font-family: 'JetBrains Mono'; 12 | src: url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/web/JetBrainsMono-Bold.eot') format('embedded-opentype'), 13 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/webfonts/JetBrainsMono-Bold.woff2') format('woff2'), 14 | url('https://raw.githubusercontent.com/JetBrains/JetBrainsMono/master/fonts/ttf/JetBrainsMono-Bold.ttf') format('truetype'); 15 | font-weight: bold; 16 | font-style: bold; 17 | } -------------------------------------------------------------------------------- /docs/styles/logo-styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --dokka-logo-image-url: url('../images/logo-icon.svg'); 3 | --dokka-logo-height: 50px; 4 | --dokka-logo-width: 50px; 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/organization/KotlinInside/4b2cdeb55873a3f08b2fa717a507ef8f2ad7835f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user guide at https://docs.gradle.org/5.1/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'KotlinInside' 11 | -------------------------------------------------------------------------------- /src/main/java/be/zvz/kotlininside/migbase64/Base64IO.java: -------------------------------------------------------------------------------- 1 | // Created on 2007-07-04 2 | package be.zvz.kotlininside.migbase64; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import static be.zvz.kotlininside.migbase64.Dictionary.CA; 9 | 10 | /** 11 | * Base64 for InputStream
Licence = BSD 12 | * 13 | * @author shamilbi shamilbi@users.sourceforge.net 14 | * @see Base64 15 | */ 16 | public class Base64IO { 17 | 18 | private static final int _8_BIT = 0xff; 19 | 20 | private static final int _6_BIT = 0x3f; 21 | 22 | private static final byte EQUAL = '='; 23 | 24 | /** 25 | * Encodes a raw InputStream into a BASE64 OutputStream representation in 26 | * accordance with RFC 2045. This implementation was inspired by MIG Base64 27 | * {@link Base64#encodeToByte(byte[], boolean)} 28 | * 29 | * @param in 30 | * @param out 31 | * @param lineSep Optional "\r\n" after 76 characters, unless end of file.
32 | * No line separator will be in breach of RFC 2045 which 33 | * specifies max 76 per line but will be a little faster. 34 | * @throws IOException 35 | */ 36 | public final static void encode(InputStream in, OutputStream out, 37 | boolean lineSep) throws IOException { 38 | // must be inBuf.length % 3 == 0 39 | final byte[] inBuf = new byte[1024 * 32 * 3]; 40 | final byte[] outBuf = new byte[4 * 19 + 2]; 41 | 42 | int eLen = inBuf.length; // Length of even 24-bits. 43 | int left = 0; 44 | int inOff = 0; 45 | boolean needsRn = false; 46 | int cc = 0; 47 | 48 | while (true) { 49 | // read full buffer 50 | final int read = in.read(inBuf, inOff, inBuf.length - inOff); 51 | 52 | if (read == -1) { 53 | // last bytes 54 | left = inOff % 3; // 0 - 2. 55 | eLen = inOff - left; // Length of even 24-bits. 56 | } else { 57 | inOff += read; 58 | if (inOff != inBuf.length) { 59 | continue; 60 | } 61 | } 62 | 63 | int outOff = 0; 64 | 65 | // encode buffer 66 | // Encode even 24-bits 67 | 68 | for (int s = 0/* , d = 0, cc = 0 */; s < eLen; ) { 69 | if (needsRn) { 70 | outBuf[outOff++] = '\r'; 71 | outBuf[outOff++] = '\n'; 72 | needsRn = false; 73 | } 74 | 75 | // Copy next three bytes into lower 24 bits of int, paying 76 | // attension to sign. 77 | int i = (inBuf[s++] & _8_BIT) << 16 78 | | (inBuf[s++] & _8_BIT) << 8 | (inBuf[s++] & _8_BIT); 79 | 80 | // Encode the int into four chars 81 | int outOff2 = outOff += 4; 82 | outBuf[--outOff2] = CA[i & _6_BIT]; 83 | outBuf[--outOff2] = CA[(i >>>= 6) & _6_BIT]; 84 | outBuf[--outOff2] = CA[(i >>>= 6) & _6_BIT]; 85 | outBuf[--outOff2] = CA[(i >>>= 6) & _6_BIT]; 86 | 87 | if (++cc == 19 /* && d < dLen - 2 */) { 88 | cc = 0; 89 | out.write(outBuf, 0, outOff); 90 | outOff = 0; 91 | 92 | // Add optional line separator 93 | if (lineSep) { 94 | needsRn = true; 95 | } 96 | } 97 | } 98 | out.write(outBuf, 0, outOff); 99 | 100 | // Pad and encode last bits if source isn't an even 24 bits. 101 | if (left > 0) { 102 | // Prepare the int 103 | int i = ((inBuf[eLen] & _8_BIT) << 10) 104 | | (left == 2 ? ((inBuf[inOff - 1] & _8_BIT) << 2) : 0); 105 | 106 | // Set last four chars 107 | outBuf[3] = EQUAL; 108 | outBuf[2] = left == 2 ? CA[i & _6_BIT] : EQUAL; 109 | outBuf[1] = CA[(i >>>= 6) & _6_BIT]; 110 | outBuf[0] = CA[i >> 6]; 111 | out.write(outBuf, 0, 4); 112 | } 113 | 114 | if (read == -1) { 115 | break; 116 | } 117 | 118 | // new block 119 | inOff = 0; 120 | } 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /src/main/java/be/zvz/kotlininside/migbase64/Dictionary.java: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.migbase64; 2 | 3 | /*package*/ interface Dictionary { 4 | byte[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(); 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/KotlinInside.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside 2 | 3 | import be.zvz.kotlininside.http.HttpInterface 4 | import be.zvz.kotlininside.security.App 5 | import be.zvz.kotlininside.security.Auth 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.LoginUser 8 | import be.zvz.kotlininside.session.user.User 9 | import java.util.* 10 | 11 | class KotlinInside private constructor( 12 | val user: User, 13 | val httpInterface: HttpInterface, 14 | private val sessionAutoRefresh: Boolean 15 | ) { 16 | val auth = Auth() 17 | lateinit var hashedAppKey: String 18 | lateinit var app: App 19 | lateinit var session: Session 20 | 21 | private fun init() { 22 | this.hashedAppKey = auth.generateHashedAppKey() 23 | this.app = App(hashedAppKey, auth.fetchAppId(hashedAppKey)) 24 | this.session = auth.login(user) 25 | 26 | if (sessionAutoRefresh) { 27 | val timer = Timer() 28 | 29 | timer.schedule( 30 | object : TimerTask() { 31 | override fun run() { 32 | if (user is LoginUser) { 33 | synchronized(instance) { 34 | instance.hashedAppKey = instance.auth.generateHashedAppKey() 35 | instance.app = 36 | App(instance.hashedAppKey, instance.auth.fetchAppId(getInstance().hashedAppKey)) 37 | instance.session = instance.auth.login(user) 38 | } 39 | } 40 | } 41 | }, 42 | 43200L * 1000, 43 | 43200L * 1000 44 | ) 45 | } 46 | } 47 | 48 | companion object { 49 | private lateinit var instance: KotlinInside 50 | 51 | /** 52 | * [KotlinInside] 인스턴스를 생성합니다. 53 | * @param user 인스턴스 생성과 동시에 로그인할 유저 54 | * @param httpInterface KotlinInside에서 사용할 HttpInterface 55 | * @param sessionAutoRefresh KotlinInside가 세션을 12시간마다 자동으로 새로고침 할지 정합니다. 56 | */ 57 | @JvmStatic 58 | @JvmOverloads 59 | @Synchronized 60 | fun createInstance(user: User, httpInterface: HttpInterface, sessionAutoRefresh: Boolean = false) { 61 | if (!::instance.isInitialized) { 62 | instance = KotlinInside(user, httpInterface, sessionAutoRefresh) 63 | instance.init() 64 | } 65 | } 66 | 67 | /** 68 | * 69 | * @return [KotlinInside] 인스턴스를 반환합니다. 70 | */ 71 | @JvmStatic 72 | fun getInstance(): KotlinInside = instance 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/article/ArticleDelete.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class ArticleDelete @JvmOverloads constructor( 12 | private val gallId: String, 13 | private val articleId: Int, 14 | private val session: Session, 15 | private val fcmToken: String = KotlinInside.getInstance().auth.fcmToken 16 | ) { 17 | data class DeleteResult( 18 | val result: Boolean, 19 | val cause: String? = null, 20 | val message: String? = null, 21 | val status: Int? = null 22 | ) 23 | 24 | /** 25 | * 글을 삭제합니다. 26 | * @exception [be.zvz.kotlininside.http.HttpException] 글을 삭제하지 못할 경우, HttpException 발생 27 | */ 28 | @Throws(HttpException::class) 29 | fun delete(): DeleteResult { 30 | val option = Request.getDefaultOption() 31 | .addMultipartParameter("id", gallId) 32 | .addMultipartParameter("client_token", fcmToken) 33 | .addMultipartParameter("no", articleId.toString()) 34 | .addMultipartParameter("mode", "board_del") 35 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 36 | 37 | if (session.user is Anonymous) { 38 | option 39 | .addMultipartParameter("write_pw", session.user.password) 40 | } else { 41 | option 42 | .addMultipartParameter("user_id", session.detail!!.userId) 43 | } 44 | 45 | var json = JsonBrowser.parse(KotlinInside.getInstance().httpInterface.upload(ApiUrl.Article.DELETE, option)) 46 | 47 | if (json.isList) { 48 | json = json.index(0) 49 | } 50 | 51 | return DeleteResult( 52 | result = json.get("result").asBoolean(), 53 | message = json.get("message").text(), 54 | status = json.get("status").asNullableInteger(), 55 | cause = json.get("cause").text() 56 | ) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/article/ArticleHitUpvote.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class ArticleHitUpvote( 12 | private val gallId: String, 13 | private val articleId: Int, 14 | private val session: Session 15 | ) { 16 | data class HitUpvoteResult( 17 | val result: Boolean, 18 | val cause: String? = null 19 | ) 20 | 21 | /** 22 | * 글을 힛갤 추천합니다. 23 | * @exception [be.zvz.kotlininside.http.HttpException] 글을 힛갤 추천하지 못할 경우, HttpException 발생 24 | */ 25 | @Throws(HttpException::class) 26 | fun upvote(): HitUpvoteResult { 27 | val option = Request.getDefaultOption() 28 | .addMultipartParameter("id", gallId) 29 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 30 | .addMultipartParameter("no", articleId.toString()) 31 | 32 | if (session.user !is Anonymous) { 33 | option 34 | .addMultipartParameter("confirm_id", session.detail!!.userId) 35 | } 36 | 37 | val json = JsonBrowser.parse(KotlinInside.getInstance().httpInterface.upload(ApiUrl.Article.HIT_UPVOTE, option)) 38 | .index(0) 39 | 40 | return HitUpvoteResult( 41 | result = json.get("result").asBoolean(), 42 | cause = json.get("cause").text() 43 | ) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/article/ArticleReport.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.session.Session 6 | import be.zvz.kotlininside.session.user.Anonymous 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class ArticleReport( 10 | private val gallId: String, 11 | private val articleId: Int, 12 | private val session: Session 13 | ) { 14 | /** 15 | * 글 신고 링크를 반환합니다. 16 | */ 17 | fun getLink(): String { 18 | val url = 19 | "${ApiUrl.Article.REPORT}?app_id=${KotlinInside.getInstance().auth.getAppId()}&id=$gallId&no=$articleId" 20 | 21 | if (session.user !is Anonymous) { 22 | url.plus("&confirm_id=${session.detail!!.userId}") 23 | } 24 | 25 | return Request.redirectUrl(url) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/article/ArticleVote.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.LoginUser 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class ArticleVote( 12 | private val gallId: String, 13 | private val articleId: Int, 14 | private val session: Session 15 | ) { 16 | data class VoteResult( 17 | val result: Boolean, 18 | val cause: String, 19 | val member: Int? = null 20 | ) 21 | 22 | /** 23 | * 글을 추천합니다. 24 | * @exception [be.zvz.kotlininside.http.HttpException] 추천이 실패할 경우, HttpException 발생 25 | */ 26 | @Throws(HttpException::class) 27 | fun upvote(): VoteResult { 28 | val option = Request.getDefaultOption() 29 | .addMultipartParameter("id", gallId) 30 | .addMultipartParameter("no", articleId.toString()) 31 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 32 | 33 | if (session.user is LoginUser) { 34 | option.addMultipartParameter("confirm_id", session.detail!!.userId) 35 | } 36 | 37 | var json = JsonBrowser.parse( 38 | KotlinInside.getInstance().httpInterface.upload( 39 | ApiUrl.Article.UPVOTE, 40 | option 41 | ) 42 | ) 43 | 44 | if (json.isList) { 45 | json = json.index(0) 46 | } 47 | 48 | return VoteResult( 49 | result = json.get("result").asBoolean(), 50 | cause = json.get("cause").safeText(), 51 | member = json.get("member").asNullableInteger() 52 | ) 53 | } 54 | 55 | /** 56 | * 글을 비추천합니다. 57 | * @exception [be.zvz.kotlininside.http.HttpException] 비추천이 실패할 경우, HttpException 발생 58 | */ 59 | @Throws(HttpException::class) 60 | fun downvote(): VoteResult { 61 | val option = Request.getDefaultOption() 62 | .addMultipartParameter("id", gallId) 63 | .addMultipartParameter("no", articleId.toString()) 64 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 65 | 66 | if (session.user is LoginUser) { 67 | option.addMultipartParameter("confirm_id", session.detail!!.userId) 68 | } 69 | 70 | val json = JsonBrowser.parse( 71 | KotlinInside.getInstance().httpInterface.upload( 72 | ApiUrl.Article.DOWNVOTE, 73 | option 74 | ) 75 | ).index(0) 76 | 77 | return VoteResult( 78 | result = json.get("result").asBoolean(), 79 | cause = json.get("cause").safeText(), 80 | member = null 81 | ) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleDelete.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.article.ArticleDelete 5 | import be.zvz.kotlininside.session.Session 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | 10 | class AsyncArticleDelete @JvmOverloads constructor( 11 | gallId: String, 12 | articleId: Int, 13 | session: Session, 14 | fcmToken: String = KotlinInside.getInstance().auth.fcmToken 15 | ) { 16 | private val articleDelete = ArticleDelete(gallId, articleId, session, fcmToken) 17 | 18 | suspend fun deleteAsync() = coroutineScope { 19 | async(Dispatchers.IO) { 20 | articleDelete.delete() 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleHitUpvote.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleHitUpvote 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncArticleHitUpvote( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session 13 | ) { 14 | private val articleHitUpvote = ArticleHitUpvote(gallId, articleId, session) 15 | 16 | suspend fun upvoteAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | articleHitUpvote.upvote() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleList.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleList 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncArticleList @JvmOverloads constructor( 10 | gallId: String, 11 | searchKeyword: String, 12 | searchType: ArticleList.SearchType = ArticleList.SearchType.ALL, 13 | page: Int = 1, 14 | recommend: Boolean = false, 15 | notice: Boolean = false, 16 | headId: Int = 0, 17 | session: Session? = null 18 | ) { 19 | @JvmOverloads 20 | constructor( 21 | gallId: String, 22 | page: Int = 1, 23 | recommend: Boolean = false, 24 | notice: Boolean = false, 25 | headId: Int = 0, 26 | session: Session? = null 27 | ) : this( 28 | gallId = gallId, 29 | searchKeyword = "", 30 | searchType = ArticleList.SearchType.ALL, 31 | page = page, 32 | recommend = recommend, 33 | notice = notice, 34 | headId = headId, 35 | session = session 36 | ) 37 | 38 | constructor( 39 | gallId: String, 40 | searchKeyword: String, 41 | page: Int = 1, 42 | recommend: Boolean = false, 43 | notice: Boolean = false, 44 | headId: Int = 0, 45 | session: Session? = null 46 | ) : this( 47 | gallId = gallId, 48 | searchKeyword = searchKeyword, 49 | searchType = ArticleList.SearchType.ALL, 50 | page = page, 51 | recommend = recommend, 52 | notice = notice, 53 | headId = headId, 54 | session = session 55 | ) 56 | 57 | private val articleList = ArticleList( 58 | gallId, 59 | searchKeyword, 60 | searchType, 61 | page, 62 | recommend, 63 | notice, 64 | headId, 65 | session 66 | ) 67 | 68 | suspend fun requestAsync() = coroutineScope { 69 | async(Dispatchers.IO) { 70 | articleList.request() 71 | } 72 | } 73 | 74 | suspend fun getGallInfoAsync() = coroutineScope { 75 | async(Dispatchers.Default) { 76 | articleList.getGallInfo() 77 | } 78 | } 79 | 80 | suspend fun getGallListAsync() = coroutineScope { 81 | async(Dispatchers.Default) { 82 | articleList.getGallList() 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleModify.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleModify 4 | import be.zvz.kotlininside.api.type.Article 5 | import be.zvz.kotlininside.session.Session 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | 10 | class AsyncArticleModify( 11 | gallId: String, 12 | articleId: Int, 13 | session: Session 14 | ) { 15 | private val articleModify = ArticleModify(gallId, articleId, session) 16 | 17 | suspend fun modifyInfoAsync() = coroutineScope { 18 | async(Dispatchers.IO) { 19 | articleModify.modifyInfo() 20 | } 21 | } 22 | 23 | suspend fun modifyAsync(article: Article, fcmToken: String = "N") = coroutineScope { 24 | async(Dispatchers.IO) { 25 | articleModify.modify(article, fcmToken) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleRead.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleRead 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncArticleRead @JvmOverloads constructor( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session? = null 13 | ) { 14 | private val articleRead = ArticleRead(gallId, articleId, session) 15 | 16 | suspend fun requestAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | articleRead.request() 19 | } 20 | } 21 | 22 | suspend fun getViewInfoAsync() = coroutineScope { 23 | async(Dispatchers.Default) { 24 | articleRead.getViewInfo() 25 | } 26 | } 27 | 28 | suspend fun getViewMainAsync() = coroutineScope { 29 | async(Dispatchers.Default) { 30 | articleRead.getViewMain() 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleReport.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleReport 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncArticleReport( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session 13 | ) { 14 | private val articleReport = ArticleReport(gallId, articleId, session) 15 | 16 | suspend fun getLinkAsync() = coroutineScope { 17 | async(Dispatchers.Default) { 18 | articleReport.getLink() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleVote.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.api.article.ArticleVote 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncArticleVote( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session 13 | ) { 14 | private val articleVote = ArticleVote(gallId, articleId, session) 15 | 16 | suspend fun upvoteAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | articleVote.upvote() 19 | } 20 | } 21 | 22 | suspend fun downvoteAsync() = coroutineScope { 23 | async(Dispatchers.IO) { 24 | articleVote.downvote() 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/article/AsyncArticleWrite.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.article 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.article.ArticleWrite 5 | import be.zvz.kotlininside.api.type.Article 6 | import be.zvz.kotlininside.session.Session 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.async 9 | import kotlinx.coroutines.coroutineScope 10 | 11 | class AsyncArticleWrite @JvmOverloads constructor( 12 | gallId: String, 13 | article: Article, 14 | session: Session, 15 | fcmToken: String = KotlinInside.getInstance().auth.fcmToken 16 | ) { 17 | private val articleWrite = ArticleWrite(gallId, article, session, fcmToken) 18 | 19 | suspend fun writeAsync() = coroutineScope { 20 | async(Dispatchers.IO) { 21 | articleWrite.write() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/comment/AsyncCommentDelete.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.comment 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.comment.CommentDelete 5 | import be.zvz.kotlininside.session.Session 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | 10 | class AsyncCommentDelete @JvmOverloads constructor( 11 | gallId: String, 12 | articleId: Int, 13 | commentId: Int, 14 | session: Session, 15 | fcmToken: String = KotlinInside.getInstance().auth.fcmToken 16 | ) { 17 | private val commentDelete = CommentDelete(gallId, articleId, commentId, session, fcmToken) 18 | 19 | suspend fun deleteAsync() = coroutineScope { 20 | async(Dispatchers.IO) { 21 | commentDelete.delete() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/comment/AsyncCommentRead.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.comment 2 | 3 | import be.zvz.kotlininside.api.comment.CommentRead 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncCommentRead( 9 | gallId: String, 10 | articleId: Int, 11 | rePage: Int 12 | ) { 13 | private val commentRead = CommentRead(gallId, articleId, rePage) 14 | 15 | suspend fun getAsync() = coroutineScope { 16 | async(Dispatchers.IO) { 17 | commentRead.request() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/comment/AsyncCommentWrite.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.comment 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.comment.CommentWrite 5 | import be.zvz.kotlininside.api.type.comment.Comment 6 | import be.zvz.kotlininside.session.Session 7 | import kotlinx.coroutines.Dispatchers 8 | import kotlinx.coroutines.async 9 | import kotlinx.coroutines.coroutineScope 10 | 11 | class AsyncCommentWrite @JvmOverloads constructor( 12 | gallId: String, 13 | articleId: Int, 14 | comment: Comment, 15 | session: Session, 16 | fcmToken: String = KotlinInside.getInstance().auth.fcmToken 17 | ) { 18 | private val commentWrite = CommentWrite(gallId, articleId, comment, session, fcmToken) 19 | 20 | suspend fun writeAsync() = coroutineScope { 21 | async(Dispatchers.IO) { 22 | commentWrite.write() 23 | } 24 | } 25 | 26 | suspend fun replyAsync(commentId: Int) = coroutineScope { 27 | async(Dispatchers.IO) { 28 | commentWrite.reply(commentId) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/dccon/AsyncDCConBuy.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.dccon 2 | 3 | import be.zvz.kotlininside.api.dccon.DCConBuy 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.session.Session 6 | import kotlinx.coroutines.Dispatchers 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | 10 | class AsyncDCConBuy( 11 | dcCon: DCCon, 12 | session: Session 13 | ) { 14 | private val dcConBuy = DCConBuy(dcCon, session) 15 | 16 | suspend fun buyAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | dcConBuy.buy() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/dccon/AsyncDCConDetail.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.dccon 2 | 3 | import be.zvz.kotlininside.api.dccon.DCConDetail 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncDCConDetail( 10 | dcCon: DCCon 11 | ) { 12 | private val dcConDetail = DCConDetail(dcCon) 13 | 14 | suspend fun getAsync() = coroutineScope { 15 | async(Dispatchers.IO) { 16 | dcConDetail.request() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/dccon/AsyncDCConList.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.dccon 2 | 3 | import be.zvz.kotlininside.api.dccon.DCConList 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncDCConList( 10 | session: Session 11 | ) { 12 | private val dcConList = DCConList(session) 13 | 14 | suspend fun requestAsync() = coroutineScope { 15 | async(Dispatchers.IO) { 16 | dcConList.request() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncGalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.GalleryRanking 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncGalleryRanking { 9 | private val galleryRanking = GalleryRanking() 10 | 11 | suspend fun getAsync() = coroutineScope { 12 | async(Dispatchers.IO) { 13 | galleryRanking.request() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncGallerySearch.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.GallerySearch 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncGallerySearch( 9 | keyword: String 10 | ) { 11 | private val gallerySearch = GallerySearch(keyword) 12 | 13 | suspend fun searchAsync() = coroutineScope { 14 | async(Dispatchers.IO) { 15 | gallerySearch.search() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncMainPage.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.MainPage 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncMainPage { 9 | private val mainPage = MainPage() 10 | 11 | suspend fun requestAsync() = coroutineScope { 12 | async(Dispatchers.IO) { 13 | mainPage.request() 14 | } 15 | } 16 | 17 | suspend fun getHitAsync() = coroutineScope { 18 | async(Dispatchers.Default) { 19 | mainPage.getHit() 20 | } 21 | } 22 | 23 | suspend fun getBestAsync() = coroutineScope { 24 | async(Dispatchers.Default) { 25 | mainPage.getBest() 26 | } 27 | } 28 | 29 | suspend fun getIssueZoomAsync() = coroutineScope { 30 | async(Dispatchers.Default) { 31 | mainPage.getIssueZoom() 32 | } 33 | } 34 | 35 | suspend fun getNewGalleryAsync() = coroutineScope { 36 | async(Dispatchers.Default) { 37 | mainPage.getNewGallery() 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncMiniGalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.MiniGalleryRanking 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncMiniGalleryRanking { 9 | private val miniGalleryRanking = MiniGalleryRanking() 10 | 11 | suspend fun getAsync() = coroutineScope { 12 | async(Dispatchers.IO) { 13 | miniGalleryRanking.request() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncMinorGalleryInfo.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.MinorGalleryInfo 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncMinorGalleryInfo( 9 | gallId: String 10 | ) { 11 | private val minorGalleryInfo = MinorGalleryInfo(gallId) 12 | 13 | suspend fun getAsync() = coroutineScope { 14 | async(Dispatchers.IO) { 15 | minorGalleryInfo.request() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncMinorGalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.MinorGalleryRanking 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncMinorGalleryRanking { 9 | private val minorGalleryRanking = MinorGalleryRanking() 10 | 11 | suspend fun getAsync() = coroutineScope { 12 | async(Dispatchers.IO) { 13 | minorGalleryRanking.request() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/AsyncTotalSearch.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic 2 | 3 | import be.zvz.kotlininside.api.generic.TotalSearch 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.async 6 | import kotlinx.coroutines.coroutineScope 7 | 8 | class AsyncTotalSearch( 9 | keyword: String 10 | ) { 11 | private val totalSearch = TotalSearch(keyword) 12 | 13 | suspend fun searchAsync() = coroutineScope { 14 | async(Dispatchers.IO) { 15 | totalSearch.search() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/minigallery/AsyncJoinMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.minigallery 2 | 3 | import be.zvz.kotlininside.api.generic.minigallery.JoinMiniGallery 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncJoinMiniGallery( 10 | gallId: String, 11 | session: Session 12 | ) { 13 | private val joinMiniGallery = JoinMiniGallery(gallId, session) 14 | 15 | suspend fun joinAsync() = coroutineScope { 16 | async(Dispatchers.IO) { 17 | joinMiniGallery.join() 18 | } 19 | } 20 | 21 | suspend fun requestMemberJoinAsync() = coroutineScope { 22 | async(Dispatchers.IO) { 23 | joinMiniGallery.requestMemberJoin() 24 | } 25 | } 26 | 27 | suspend fun requestMemberJoinOkAsync() = coroutineScope { 28 | async(Dispatchers.IO) { 29 | joinMiniGallery.requestMemberJoinOk() 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/minigallery/AsyncQuitMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.minigallery 2 | 3 | import be.zvz.kotlininside.api.generic.minigallery.QuitMiniGallery 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncQuitMiniGallery( 10 | gallId: String, 11 | session: Session 12 | ) { 13 | private val quitMiniGallery = QuitMiniGallery(gallId, session) 14 | 15 | suspend fun quitAsync() = coroutineScope { 16 | async(Dispatchers.IO) { 17 | quitMiniGallery.quit() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/userinfo/AsyncCheckJoinedMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.userinfo 2 | 3 | import be.zvz.kotlininside.api.generic.userinfo.CheckJoinedMiniGallery 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncCheckJoinedMiniGallery( 10 | session: Session 11 | ) { 12 | private val checkJoinMiniGallery = CheckJoinedMiniGallery(session) 13 | 14 | suspend fun requestAsync() = coroutineScope { 15 | async(Dispatchers.IO) { 16 | checkJoinMiniGallery.request() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/userinfo/AsyncCheckManagedGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.userinfo 2 | 3 | import be.zvz.kotlininside.api.generic.userinfo.CheckManagedGallery 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncCheckManagedGallery( 10 | session: Session 11 | ) { 12 | private val checkManagedGallery = CheckManagedGallery(session) 13 | 14 | suspend fun requestAsync() = coroutineScope { 15 | async(Dispatchers.IO) { 16 | checkManagedGallery.request() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/userinfo/AsyncModifyMyGall.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.userinfo 2 | 3 | import be.zvz.kotlininside.api.generic.userinfo.ModifyMyGall 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncModifyMyGall( 10 | gallName: String, 11 | gallId: String, 12 | session: Session 13 | ) { 14 | private val modifyMyGall = ModifyMyGall(gallName, gallId, session) 15 | 16 | suspend fun requestAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | modifyMyGall.request() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/generic/userinfo/AsyncMyGall.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.generic.userinfo 2 | 3 | import be.zvz.kotlininside.api.generic.userinfo.MyGall 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncMyGall( 10 | session: Session 11 | ) { 12 | private val myGall = MyGall(session) 13 | 14 | suspend fun requestAsync() = coroutineScope { 15 | async(Dispatchers.IO) { 16 | myGall.request() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncChangeHeadText.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.ChangeHeadText 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncChangeHeadText( 10 | gallId: String, 11 | articleId: Int, 12 | headTextId: Int, 13 | session: Session 14 | ) { 15 | private val changeHeadText = ChangeHeadText(gallId, articleId, headTextId, session) 16 | 17 | suspend fun requestAsync() = coroutineScope { 18 | async(Dispatchers.IO) { 19 | changeHeadText.request() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncGallerySetting.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.GallerySetting 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncGallerySetting( 10 | gallId: String, 11 | session: Session 12 | ) { 13 | private val gallerySetting = GallerySetting(gallId, session) 14 | 15 | suspend fun getLinkAsync() = coroutineScope { 16 | async(Dispatchers.IO) { 17 | gallerySetting.getLink() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncNoMemberBlock.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.NoMemberBlock 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncNoMemberBlock( 10 | session: Session, 11 | gallId: String, 12 | option: NoMemberBlock.BlockOption = NoMemberBlock.BlockOption() 13 | ) { 14 | private val noMemberBlock = NoMemberBlock( 15 | session, 16 | gallId, 17 | option 18 | ) 19 | 20 | suspend fun blockAsync() = coroutineScope { 21 | async(Dispatchers.IO) { 22 | noMemberBlock.block() 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncNotice.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.Notice 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncNotice( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session 13 | ) { 14 | private val notice = Notice(gallId, articleId, session) 15 | 16 | suspend fun requestAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | notice.request() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncRecommend.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.Recommend 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncRecommend( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session 13 | ) { 14 | private val recommend = Recommend(gallId, articleId, session) 15 | 16 | suspend fun requestAsync() = coroutineScope { 17 | async(Dispatchers.IO) { 18 | recommend.request() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/async/management/AsyncUserBlock.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.async.management 2 | 3 | import be.zvz.kotlininside.api.management.UserBlock 4 | import be.zvz.kotlininside.session.Session 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.coroutineScope 8 | 9 | class AsyncUserBlock @JvmOverloads constructor( 10 | gallId: String, 11 | articleId: Int, 12 | session: Session, 13 | option: UserBlock.BlockOption = UserBlock.BlockOption() 14 | ) { 15 | private val userBlock = UserBlock(gallId, articleId, session, option) 16 | 17 | suspend fun blockAsync() = coroutineScope { 18 | async(Dispatchers.IO) { 19 | userBlock.block() 20 | } 21 | } 22 | 23 | suspend fun getLinkAsync() = coroutineScope { 24 | async(Dispatchers.IO) { 25 | userBlock.getLink() 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/comment/CommentDelete.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.comment 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class CommentDelete @JvmOverloads constructor( 12 | private val gallId: String, 13 | private val articleId: Int, 14 | private val commentId: Int, 15 | private val session: Session, 16 | private val fcmToken: String = KotlinInside.getInstance().auth.fcmToken 17 | ) { 18 | data class DeleteResult( 19 | val result: Boolean, 20 | val cause: String? = null 21 | ) 22 | 23 | /** 24 | * 댓글을 삭제합니다. 25 | * @exception [be.zvz.kotlininside.http.HttpException] 댓글을 삭제하지 못할 경우, HttpException 발생 26 | */ 27 | @Throws(HttpException::class) 28 | fun delete(): DeleteResult { 29 | val option = Request.getDefaultOption() 30 | .addMultipartParameter("id", gallId) 31 | .addMultipartParameter("no", articleId.toString()) 32 | .addMultipartParameter("comment_no", commentId.toString()) 33 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 34 | .addMultipartParameter("client_token", fcmToken) 35 | .addMultipartParameter("mode", "comment_del") 36 | 37 | if (session.user is Anonymous) { 38 | option 39 | .addMultipartParameter("comment_pw", session.user.password) 40 | .addMultipartParameter("board_id", "") 41 | } else { 42 | option 43 | .addMultipartParameter("user_id", session.detail!!.userId) 44 | .addMultipartParameter("board_id", session.user.id) 45 | } 46 | 47 | val json = 48 | JsonBrowser.parse(KotlinInside.getInstance().httpInterface.upload(ApiUrl.Comment.DELETE, option)).index(0) 49 | 50 | return DeleteResult( 51 | result = json.get("result").asBoolean(), 52 | cause = json.get("cause").text() 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/comment/CommentRead.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.comment 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.api.type.comment.Comment 6 | import be.zvz.kotlininside.api.type.comment.DCConComment 7 | import be.zvz.kotlininside.api.type.comment.StringComment 8 | import be.zvz.kotlininside.http.HttpException 9 | import be.zvz.kotlininside.http.Request 10 | import be.zvz.kotlininside.json.JsonBrowser 11 | import be.zvz.kotlininside.value.ApiUrl 12 | 13 | class CommentRead( 14 | private val gallId: String, 15 | private val articleId: Int, 16 | private val rePage: Int 17 | ) { 18 | data class ReadResult( 19 | val totalComment: Int, 20 | val totalPage: Int, 21 | val rePage: Int, 22 | val commentList: List 23 | ) 24 | 25 | data class CommentData( 26 | val memberIcon: Int, 27 | val ipData: String?, 28 | val gallerCon: String?, 29 | val name: String, 30 | val userId: String, 31 | val content: Comment, 32 | val identifier: Int, 33 | val dateTime: String, 34 | val isReply: Boolean, 35 | val isDeleteFlag: String? 36 | ) 37 | 38 | /** 39 | * 댓글 데이터를 읽어옵니다. 40 | * @exception [be.zvz.kotlininside.http.HttpException] 댓글을 읽어오지 못할 경우, HttpException 발생 41 | */ 42 | @Throws(HttpException::class) 43 | fun request(): ReadResult { 44 | val url = 45 | "${ApiUrl.Comment.READ}?id=$gallId&no=$articleId&re_page=$rePage&app_id=${KotlinInside.getInstance().auth.getAppId()}" 46 | 47 | val json = JsonBrowser.parse( 48 | KotlinInside.getInstance().httpInterface.get( 49 | Request.redirectUrl(url), 50 | Request.getDefaultOption() 51 | ) 52 | ) 53 | .index(0) 54 | 55 | return ReadResult( 56 | totalComment = json.get("total_comment").asInteger(), 57 | totalPage = json.get("total_page").asInteger(), 58 | rePage = json.get("re_page").asInteger(), 59 | commentList = mutableListOf().apply { 60 | json.get("comment_list").values().forEach { 61 | add( 62 | CommentData( 63 | memberIcon = it.get("member_icon").asInteger(), 64 | ipData = it.get("ipData").text(), 65 | gallerCon = it.get("gallercon").text(), 66 | name = it.get("name").safeText(), 67 | userId = it.get("user_id").safeText(), 68 | content = it.get("dccon").run { 69 | when { 70 | isNull -> { 71 | StringComment( 72 | memo = it.get("comment_memo").safeText() 73 | ) 74 | } 75 | else -> { 76 | DCConComment( 77 | dcCon = DCCon( 78 | imgLink = safeText(), 79 | memo = it.get("comment_memo").safeText(), 80 | detailIndex = it.get("dccon_detail_idx").asInteger() 81 | ) 82 | ) 83 | } 84 | } 85 | }, 86 | identifier = it.get("comment_no").asInteger(), 87 | dateTime = it.get("date_time").safeText(), 88 | isReply = it.get("under_step").asBoolean(), 89 | isDeleteFlag = it.get("is_delete_flag").text() 90 | ) 91 | ) 92 | } 93 | } 94 | ) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/dccon/DCConBuy.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.dccon 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.http.HttpException 6 | import be.zvz.kotlininside.http.Request 7 | import be.zvz.kotlininside.json.JsonBrowser 8 | import be.zvz.kotlininside.session.Session 9 | import be.zvz.kotlininside.session.user.Anonymous 10 | import be.zvz.kotlininside.value.ApiUrl 11 | 12 | class DCConBuy( 13 | private val dcCon: DCCon, 14 | private val session: Session 15 | ) { 16 | data class BuyResult( 17 | val result: Int, 18 | val msg: String 19 | ) 20 | 21 | /** 22 | * 디시콘을 구매합니다. 23 | * @return [BuyResult] 구매 결과를 반환합니다. 24 | */ 25 | fun buy(): BuyResult { 26 | if (session.user is Anonymous) { 27 | throw HttpException( 28 | RuntimeException("Anonymous 세션은 DCConBuy를 이용할 수 없습니다.") 29 | ) 30 | } 31 | 32 | val option = Request.getDefaultOption() 33 | .addMultipartParameter("user_id", session.detail!!.userId) 34 | .addMultipartParameter("package_idx", dcCon.packageIndex.toString()) 35 | .addMultipartParameter("type", "buy_dccon") 36 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 37 | 38 | val json = JsonBrowser.parse( 39 | KotlinInside.getInstance().httpInterface.upload( 40 | ApiUrl.DCCon.DCCON, 41 | option 42 | ) 43 | ) 44 | 45 | return BuyResult( 46 | result = json.get("result").asInteger(), 47 | msg = json.get("msg").safeText() 48 | ) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/dccon/DCConDetail.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.dccon 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.utils.StringUtil 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class DCConDetail( 11 | private val dcCon: DCCon 12 | ) { 13 | data class DetailResult( 14 | val info: List = listOf(), 15 | val detail: List = listOf() 16 | ) 17 | 18 | data class DCConInfo( 19 | val packageIndex: Int, 20 | val mainImg: String, 21 | val title: String, 22 | val description: String, 23 | val mandu: Int, 24 | val getState: Boolean 25 | ) 26 | 27 | /** 28 | * 디시콘 정보를 받아오는 메소드입니다. 29 | * @return [DetailResult] 디시콘 정보를 반환합니다. 30 | */ 31 | fun request(): DetailResult { 32 | val option = Request.getDefaultOption() 33 | .addMultipartParameter("package_idx", dcCon.packageIndex.toString()) 34 | .addMultipartParameter("type", "package_detail") 35 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 36 | 37 | val json = JsonBrowser.parse( 38 | KotlinInside.getInstance().httpInterface.upload( 39 | ApiUrl.DCCon.DCCON, 40 | option 41 | ) 42 | ) 43 | 44 | return when { 45 | json.isList -> { 46 | DetailResult() 47 | } 48 | else -> DetailResult( 49 | info = mutableListOf().apply { 50 | json.get("info").values().forEach { 51 | add( 52 | DCConInfo( 53 | packageIndex = it.get("package_idx").asInteger(), 54 | mainImg = it.get("main_img").safeText(), 55 | title = it.get("title").safeText(), 56 | description = it.get("description").safeText(), 57 | mandu = it.get("mandu").asInteger(), 58 | getState = StringUtil.ynToBoolean(it.get("get_state").safeText()) 59 | ) 60 | ) 61 | } 62 | }, 63 | detail = mutableListOf().apply { 64 | json.get("detail").values().forEach { 65 | add( 66 | DCCon( 67 | imgLink = it.get("img").safeText() 68 | ) 69 | ) 70 | } 71 | } 72 | ) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/dccon/DCConInsert.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.dccon 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.utils.StringUtil 10 | import be.zvz.kotlininside.value.ApiUrl 11 | 12 | class DCConInsert( 13 | val dcCon: DCCon, 14 | val session: Session 15 | ) { 16 | data class InsertResult( 17 | val result: Boolean, 18 | val newList: String?, 19 | val imageSource: String?, 20 | val alternativeText: String?, 21 | val imageTag: String? 22 | ) 23 | 24 | fun request(): InsertResult { 25 | val json = JsonBrowser.parse( 26 | KotlinInside.getInstance().httpInterface.upload( 27 | ApiUrl.DCCon.DCCON, 28 | Request.getDefaultOption().apply { 29 | if (session.user !is Anonymous) { 30 | addMultipartParameter("user_id", session.detail!!.userId) 31 | } 32 | } 33 | .addMultipartParameter("package_idx", dcCon.packageIndex.toString()) 34 | .addMultipartParameter("detail_idx", dcCon.detailIndex.toString()) 35 | .addMultipartParameter("type", "insert") 36 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 37 | ) 38 | ) 39 | return InsertResult( 40 | result = StringUtil.okToBoolean(json.get("result").safeText()), 41 | newList = json.get("new_list").text(), 42 | imageSource = json.get("img_src").text(), 43 | alternativeText = json.get("alt").text(), 44 | imageTag = json.get("img_tag").text() 45 | ) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/dccon/DCConList.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.dccon 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.DCCon 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.LoginUser 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class DCConList( 12 | private val session: Session 13 | ) { 14 | data class ListResult( 15 | val tab: List, 16 | val list: List> 17 | ) 18 | 19 | fun request(): ListResult { 20 | val option = Request.getDefaultOption() 21 | .addMultipartParameter("type", "list") 22 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 23 | 24 | if (session.user is LoginUser) { 25 | option.addMultipartParameter("user_id", session.detail!!.userId) 26 | } 27 | 28 | val json = JsonBrowser.parse( 29 | KotlinInside.getInstance().httpInterface.upload( 30 | ApiUrl.DCCon.DCCON, 31 | option 32 | ) 33 | ) 34 | 35 | return ListResult( 36 | tab = mutableListOf().apply { 37 | json.get("tab").values().forEach { 38 | add( 39 | DCCon( 40 | packageIndex = it.get("package_idx").asInteger(), 41 | title = it.get("title").safeText(), 42 | imgLink = it.get("img").safeText() 43 | ) 44 | ) 45 | } 46 | }, 47 | list = mutableListOf>().apply { 48 | json.get("list").values().forEach { list -> 49 | add( 50 | mutableListOf().apply { 51 | list.values().forEach { 52 | add( 53 | DCCon( 54 | detailIndex = it.get("detail_idx").asInteger(), 55 | packageIndex = it.get("package_idx").asInteger(), 56 | title = it.get("title").safeText(), 57 | imgLink = it.get("img").safeText() 58 | ) 59 | ) 60 | } 61 | } 62 | ) 63 | } 64 | } 65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/GalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class GalleryRanking { 10 | enum class RankType { 11 | UP, 12 | DOWN, 13 | STOP, 14 | UNKNOWN 15 | } 16 | 17 | data class RankingItem( 18 | val gallLink: String, 19 | val gallId: String, 20 | val gallName: String, 21 | val rankType: RankType, 22 | val rank: Int, 23 | val rankUpdown: Int 24 | ) 25 | 26 | /** 27 | * 정식 갤러리 랭킹을 불러옵니다. 28 | * @return 정식 갤러리 랭킹을 반환합니다. 29 | * @exception [be.zvz.kotlininside.http.HttpException] 데이터를 불러오지 못할 경우, HttpException 발생 30 | */ 31 | @Throws(HttpException::class) 32 | fun request(): List { 33 | return mutableListOf().apply { 34 | val json = JsonBrowser.parse( 35 | KotlinInside.getInstance().httpInterface.get( 36 | ApiUrl.MainInfo.GALLERY_RANKING, 37 | Request.getDefaultOption() 38 | ) 39 | ) 40 | json.values().forEach { 41 | add( 42 | RankingItem( 43 | gallLink = it.get("link").text()!!, 44 | gallId = it.get("id").text()!!, 45 | gallName = it.get("category").text()!!, 46 | rankType = it.get("rank_type").text()!!.let { rankTypeString -> 47 | return@let when (rankTypeString) { 48 | "up" -> RankType.UP 49 | "stop" -> RankType.STOP 50 | "down" -> RankType.DOWN 51 | else -> RankType.UNKNOWN 52 | } 53 | }, 54 | rank = it.get("num").asInteger(), 55 | rankUpdown = it.get("rank").asInteger() 56 | ) 57 | ) 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/GallerySearch.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.Gallery 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class GallerySearch( 10 | private val keyword: String 11 | ) { 12 | data class GallerySearchResult( 13 | val mainGallery: List, 14 | val minorGallery: List, 15 | val mainRecommendGallery: List, 16 | val minorRecommendGallery: List 17 | ) 18 | 19 | /** 20 | * 갤러리 목록을 검색하고, 검색 결과를 받아옵니다. 21 | * 22 | * @return 갤러리 목록 검색 결과를 반환합니다. 23 | */ 24 | fun search(): GallerySearchResult { 25 | val option = Request.getDefaultOption() 26 | .addMultipartParameter("keyword", keyword) 27 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 28 | 29 | val json = JsonBrowser.parse( 30 | KotlinInside.getInstance().httpInterface.upload( 31 | ApiUrl.Search.SEARCH, 32 | option 33 | ) 34 | ) 35 | 36 | return GallerySearchResult( 37 | mainGallery = mutableListOf().apply { 38 | json.get("main_gall").values().forEach { 39 | add( 40 | Gallery( 41 | title = it.get("title").safeText(), 42 | id = it.get("id").safeText() 43 | ) 44 | ) 45 | } 46 | }, 47 | minorGallery = mutableListOf().apply { 48 | json.get("minor_gall").values().forEach { 49 | add( 50 | Gallery( 51 | title = it.get("title").safeText(), 52 | id = it.get("id").safeText() 53 | ) 54 | ) 55 | } 56 | }, 57 | mainRecommendGallery = mutableListOf().apply { 58 | json.get("main_recomm_gall").values().forEach { 59 | add( 60 | Gallery( 61 | title = it.get("title").safeText(), 62 | id = it.get("id").safeText() 63 | ) 64 | ) 65 | } 66 | }, 67 | minorRecommendGallery = mutableListOf().apply { 68 | json.get("minor_recomm_gall").values().forEach { 69 | add( 70 | Gallery( 71 | title = it.get("title").safeText(), 72 | id = it.get("id").safeText() 73 | ) 74 | ) 75 | } 76 | } 77 | ) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/MainPage.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class MainPage { 10 | private lateinit var json: JsonBrowser 11 | 12 | data class Article( 13 | val gallId: String, 14 | val articleId: Int, 15 | val gallName: String? = null, 16 | val title: String, 17 | val thumbnail: String 18 | ) 19 | 20 | data class NewGallery( 21 | val id: String, 22 | val title: String 23 | ) 24 | 25 | /** 26 | * 클래스의 메소드들을 사용하기 전, 이 메소드를 호출해주세요. (권장) 27 | * @exception [be.zvz.kotlininside.http.HttpException] 글 목록을 불러오지 못할 경우, HttpException 발생 28 | */ 29 | @Throws(HttpException::class) 30 | fun request() { 31 | json = JsonBrowser.parse( 32 | KotlinInside.getInstance().httpInterface.get( 33 | ApiUrl.MainInfo.APP_MAIN, 34 | Request.getDefaultOption() 35 | ) 36 | ) 37 | .index(0) 38 | } 39 | 40 | /** 41 | * 메인 화면에 표시되어 있는 Hit갤 게시물 목록을 가져옵니다. 42 | * @exception [be.zvz.kotlininside.http.HttpException] 글 목록을 불러오지 못할 경우, HttpException 발생 43 | */ 44 | @Throws(HttpException::class) 45 | fun getHit(): List
{ 46 | if (!::json.isInitialized) { 47 | request() 48 | } 49 | 50 | return mutableListOf
().apply { 51 | json.get("hit").values().forEach { 52 | add( 53 | Article( 54 | gallId = it.get("id").safeText(), 55 | articleId = it.get("no").`as`(Int::class.java), 56 | title = it.get("title").safeText(), 57 | thumbnail = it.get("thumbnail").safeText() 58 | ) 59 | ) 60 | } 61 | } 62 | } 63 | 64 | /** 65 | * 메인 화면에 표시되어 있는 베스트 게시물 목록을 가져옵니다. 66 | * @exception [be.zvz.kotlininside.http.HttpException] 글 목록을 불러오지 못할 경우, HttpException 발생 67 | */ 68 | @Throws(HttpException::class) 69 | fun getBest(): List
{ 70 | if (!::json.isInitialized) { 71 | request() 72 | } 73 | 74 | return mutableListOf
().apply { 75 | json.get("best").values().forEach { 76 | add( 77 | Article( 78 | gallId = it.get("id").safeText(), 79 | articleId = it.get("no").asInteger(), 80 | gallName = it.get("gall_name").text(), 81 | title = it.get("title").safeText(), 82 | thumbnail = it.get("thumbnail").safeText() 83 | ) 84 | ) 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * 메인 화면에 표시되어 있는 이슈줌갤 게시물 목록을 가져옵니다. 91 | * @exception [be.zvz.kotlininside.http.HttpException] 글 목록을 불러오지 못할 경우, HttpException 발생 92 | */ 93 | @Throws(HttpException::class) 94 | fun getIssueZoom(): List
{ 95 | if (!::json.isInitialized) { 96 | request() 97 | } 98 | 99 | return mutableListOf
().apply { 100 | json.get("issuezoom").values().forEach { 101 | add( 102 | Article( 103 | gallId = it.get("id").safeText(), 104 | articleId = it.get("no").asInteger(), 105 | gallName = it.get("gall_name").text(), 106 | title = it.get("title").safeText(), 107 | thumbnail = it.get("thumbnail").safeText() 108 | ) 109 | ) 110 | } 111 | } 112 | } 113 | 114 | /** 115 | * 메인 화면에 표시되어 있는 신규 갤러리 목록을 가져옵니다. 116 | * @exception [be.zvz.kotlininside.http.HttpException] 신규 갤러리 목록을 불러오지 못할 경우, HttpException 발생 117 | */ 118 | @Throws(HttpException::class) 119 | fun getNewGallery(): List { 120 | if (!::json.isInitialized) { 121 | request() 122 | } 123 | 124 | return mutableListOf().apply { 125 | json.get("new_gallery").values().forEach { 126 | add( 127 | NewGallery( 128 | id = it.get("id").safeText(), 129 | title = it.get("title").safeText() 130 | ) 131 | ) 132 | } 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/MiniGalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class MiniGalleryRanking { 10 | enum class RankType { 11 | UP, 12 | DOWN, 13 | STOP, 14 | UNKNOWN 15 | } 16 | 17 | data class RankingItem( 18 | val gallLink: String, 19 | val gallId: String, 20 | val gallName: String, 21 | val rankType: RankType, 22 | val rank: Int, 23 | val rankUpdown: Int 24 | ) 25 | 26 | /** 27 | * 미니 갤러리 랭킹을 불러옵니다. 28 | * @return 미니 갤러리 랭킹을 반환합니다. 29 | * @exception [be.zvz.kotlininside.http.HttpException] 데이터를 불러오지 못할 경우, HttpException 발생 30 | */ 31 | @Throws(HttpException::class) 32 | fun request(): List { 33 | return mutableListOf().apply { 34 | val json = JsonBrowser.parse( 35 | KotlinInside.getInstance().httpInterface.get( 36 | ApiUrl.MainInfo.MINI_GALLERY_RANKING, 37 | Request.getDefaultOption() 38 | ) 39 | ) 40 | json.values().forEach { 41 | add( 42 | RankingItem( 43 | gallLink = it.get("link").text()!!, 44 | gallId = it.get("id").text()!!, 45 | gallName = it.get("ko_name").text()!!, 46 | rankType = it.get("rank_type").text()!!.let { rankTypeString -> 47 | return@let when (rankTypeString) { 48 | "up" -> RankType.UP 49 | "stop" -> RankType.STOP 50 | "down" -> RankType.DOWN 51 | else -> RankType.UNKNOWN 52 | } 53 | }, 54 | rank = it.get("rank").asInteger(), 55 | rankUpdown = it.get("rank_updown").asInteger() 56 | ) 57 | ) 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/MinorGalleryInfo.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.value.ApiUrl 7 | 8 | class MinorGalleryInfo( 9 | private val gallId: String 10 | ) { 11 | data class MiniGalleryInfo( 12 | val hide: Int, 13 | val totalMember: Int, 14 | val memberLimit: Int, 15 | val isMember: Boolean 16 | ) 17 | 18 | data class InfoResult( 19 | val id: String, 20 | val koName: String, 21 | val image: String? = null, 22 | val description: String? = null, 23 | val manager: Manager, 24 | val subManager: List, 25 | val createDate: String, 26 | val new: Boolean, 27 | val hotState: String, 28 | val totalCount: String, 29 | val categoryName: String, 30 | val mini: MiniGalleryInfo? = null 31 | ) 32 | 33 | data class Manager( 34 | val isMaster: Boolean, 35 | val id: String, 36 | val name: String 37 | ) 38 | 39 | /** 40 | * 갤러리 정보를 받아옵니다. 41 | * 42 | * @return 갤러리 정보를 반환합니다. 43 | */ 44 | fun request(): InfoResult { 45 | val option = Request.getDefaultOption() 46 | .addMultipartParameter("id", gallId) 47 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 48 | 49 | val json = JsonBrowser.parse( 50 | KotlinInside.getInstance().httpInterface.upload( 51 | ApiUrl.Gallery.MINOR_INFO, 52 | option 53 | ) 54 | ).index(0) 55 | 56 | val miniGalleryInfo = json.get("mini") 57 | return InfoResult( 58 | id = json.get("id").safeText(), 59 | koName = json.get("ko_name").safeText(), 60 | image = json.get("img").text(), 61 | description = json.get("mgallery_desc").text(), 62 | manager = Manager( 63 | isMaster = true, 64 | id = json.get("master_id").safeText(), 65 | name = json.get("master_name").safeText() 66 | ), 67 | subManager = mutableListOf().apply { 68 | json.get("submanager").values().forEach { 69 | add( 70 | Manager( 71 | isMaster = false, 72 | id = it.get("id").safeText(), 73 | name = it.get("name").safeText() 74 | ) 75 | ) 76 | } 77 | }, 78 | createDate = json.get("create_dt").safeText(), 79 | new = json.get("new").asBoolean(), 80 | hotState = json.get("hot_state").safeText(), 81 | totalCount = json.get("total_count").safeText(), 82 | categoryName = json.get("cate_name").safeText(), 83 | mini = if (!miniGalleryInfo.isNull) { 84 | MiniGalleryInfo( 85 | hide = miniGalleryInfo.get("gall_hide").asInteger(), 86 | totalMember = miniGalleryInfo.get("total_member").asInteger(), 87 | memberLimit = miniGalleryInfo.get("member_limit").asInteger(), 88 | isMember = miniGalleryInfo.get("member_ok").asBoolean() 89 | ) 90 | } else { 91 | null 92 | } 93 | ) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/MinorGalleryRanking.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.HttpException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.value.ApiUrl 8 | 9 | class MinorGalleryRanking { 10 | enum class RankType { 11 | UP, 12 | DOWN, 13 | STOP, 14 | UNKNOWN 15 | } 16 | 17 | data class RankingItem( 18 | val gallLink: String, 19 | val gallId: String, 20 | val gallName: String, 21 | val rankType: RankType, 22 | val rank: Int, 23 | val rankUpdown: Int 24 | ) 25 | 26 | /** 27 | * 마이너 갤러리 랭킹을 불러옵니다. 28 | * @return 마이너 갤러리 랭킹을 반환합니다. 29 | * @exception [be.zvz.kotlininside.http.HttpException] 데이터를 불러오지 못할 경우, HttpException 발생 30 | */ 31 | @Throws(HttpException::class) 32 | fun request(): List { 33 | return mutableListOf().apply { 34 | val json = JsonBrowser.parse( 35 | KotlinInside.getInstance().httpInterface.get( 36 | ApiUrl.MainInfo.MINOR_GALLERY_RANKING, 37 | Request.getDefaultOption() 38 | ) 39 | ) 40 | json.values().forEach { 41 | add( 42 | RankingItem( 43 | gallLink = it.get("link").text()!!, 44 | gallId = it.get("id").text()!!, 45 | gallName = it.get("ko_name").text()!!, 46 | rankType = it.get("rank_type").text()!!.let { rankTypeString -> 47 | return@let when (rankTypeString) { 48 | "up" -> RankType.UP 49 | "stop" -> RankType.STOP 50 | "down" -> RankType.DOWN 51 | else -> RankType.UNKNOWN 52 | } 53 | }, 54 | rank = it.get("rank").asInteger(), 55 | rankUpdown = it.get("rank_updown").asInteger() 56 | ) 57 | ) 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/MovieUpload.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.content.MovieContent 5 | import be.zvz.kotlininside.http.HttpInterface 6 | import be.zvz.kotlininside.http.Request 7 | import be.zvz.kotlininside.json.JsonBrowser 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | import java.io.IOException 11 | 12 | /** 13 | * [be.zvz.kotlininside.api.type.content.MovieContent] 업로드를 위한 API 클래스 14 | */ 15 | class MovieUpload @JvmOverloads constructor( 16 | val gallId: String, 17 | val content: MovieContent, 18 | val checkRestriction: Boolean = true 19 | ) { 20 | class UploadException( 21 | val checkResult: CheckResult 22 | ) : IOException(checkResult.cause) 23 | 24 | data class UploadResult( 25 | val msg: String?, 26 | val fileId: Int?, 27 | val thumbnailUrls: List?, 28 | val width: Int?, 29 | val height: Int? 30 | ) 31 | 32 | data class CheckResult( 33 | val result: Boolean, 34 | val cause: String? = null 35 | ) 36 | 37 | @Throws(UploadException::class) 38 | fun upload(): UploadResult { 39 | if (checkRestriction && KotlinInside.getInstance().session.user is Anonymous) { 40 | val json = JsonBrowser.parse( 41 | KotlinInside.getInstance().httpInterface.get( 42 | ApiUrl.Upload.CHECK_UPLOAD_RESTRICTION + 43 | "?app_id=${KotlinInside.getInstance().auth.getAppId()}" + 44 | "&id=$gallId" + 45 | "&mode=movie", 46 | Request.getDefaultOption() 47 | ) 48 | ) 49 | val checkResult = CheckResult( 50 | result = json.get("result").asBoolean(), 51 | cause = json.get("cause").text() 52 | ) 53 | 54 | if (!checkResult.result) { 55 | throw UploadException(checkResult) 56 | } 57 | } 58 | 59 | val result = JsonBrowser.parse( 60 | KotlinInside.getInstance().httpInterface.upload( 61 | ApiUrl.Upload.MOVIE, 62 | Request.getDefaultOption().apply { 63 | addMultipartParameter("id", gallId) 64 | addMultipartFile( 65 | "avatar", 66 | HttpInterface.Option.FileInfo( 67 | content.stream, 68 | content.mimeType 69 | ) 70 | ) 71 | } 72 | ) 73 | ) 74 | return UploadResult( 75 | msg = result.get("msg").text(), 76 | fileId = result.get("file_no").asNullableInteger()?.apply { 77 | content.uploaded = true 78 | content.fileId = this 79 | }, 80 | thumbnailUrls = result.get("thum_url_arr").run { 81 | if (!isNull) { 82 | mutableListOf().apply { 83 | values().forEach { 84 | add(it.safeText()) 85 | } 86 | } 87 | } else { 88 | null 89 | } 90 | }, 91 | width = result.get("width").asNullableInteger()?.apply { 92 | content.info.width = this 93 | }, 94 | height = result.get("height").asNullableInteger()?.apply { 95 | content.info.height = this 96 | } 97 | ) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/minigallery/JoinMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.minigallery 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.Anonymous 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class JoinMiniGallery( 11 | private val gallId: String, 12 | private val session: Session 13 | ) { 14 | data class MemberJoinResult( 15 | val result: Boolean, 16 | val joinQuestion: String 17 | ) 18 | 19 | data class MemberJoinOkResult( 20 | val result: Boolean, 21 | val cause: String, 22 | val status: String 23 | ) 24 | 25 | fun join(): Pair { 26 | val memberJoinResult = requestMemberJoin() 27 | val memberJoinOkResult = requestMemberJoinOk() 28 | 29 | return Pair(memberJoinResult, memberJoinOkResult) 30 | } 31 | 32 | fun requestMemberJoin(): MemberJoinResult { 33 | if (session.user is Anonymous) { 34 | throw RuntimeException("Anonymous는 requestMemberJoin을 사용할 수 없습니다.") 35 | } 36 | 37 | val option = Request.getDefaultOption() 38 | .addMultipartParameter("user_id", session.detail!!.userId) 39 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 40 | .addMultipartParameter("id", gallId) 41 | 42 | val json = JsonBrowser.parse( 43 | KotlinInside.getInstance().httpInterface.upload( 44 | ApiUrl.MiniGallery.JOIN, 45 | option 46 | ) 47 | ).index(0) 48 | 49 | return MemberJoinResult( 50 | result = json.get("result").asBoolean(), 51 | joinQuestion = json.get("join_question").safeText() 52 | ) 53 | } 54 | 55 | fun requestMemberJoinOk(): MemberJoinOkResult { 56 | if (session.user is Anonymous) { 57 | throw RuntimeException("Anonymous는 requestMemberJoinOk을 사용할 수 없습니다.") 58 | } 59 | 60 | val option = Request.getDefaultOption() 61 | .addMultipartParameter("user_id", session.detail!!.userId) 62 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 63 | .addMultipartParameter("id", gallId) 64 | 65 | val json = JsonBrowser.parse( 66 | KotlinInside.getInstance().httpInterface.upload( 67 | ApiUrl.MiniGallery.JOIN_OK, 68 | option 69 | ) 70 | ).index(0) 71 | 72 | return MemberJoinOkResult( 73 | result = json.get("result").asBoolean(), 74 | cause = json.get("cause").safeText(), 75 | status = json.get("status").safeText() 76 | ) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/minigallery/QuitMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.minigallery 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.Anonymous 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class QuitMiniGallery( 11 | private val gallId: String, 12 | private val session: Session 13 | ) { 14 | data class MemberQuitResult( 15 | val result: Boolean 16 | ) 17 | 18 | fun quit(): MemberQuitResult { 19 | if (session.user is Anonymous) { 20 | throw RuntimeException("Anonymous는 QuitMiniGallery를 사용할 수 없습니다.") 21 | } 22 | 23 | val option = Request.getDefaultOption() 24 | .addMultipartParameter("user_id", session.detail!!.userId) 25 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 26 | .addMultipartParameter("id", gallId) 27 | 28 | val json = JsonBrowser.parse( 29 | KotlinInside.getInstance().httpInterface.upload( 30 | ApiUrl.MiniGallery.QUIT, 31 | option 32 | ) 33 | ).index(0) 34 | 35 | return MemberQuitResult( 36 | result = json.get("result").asBoolean() 37 | ) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/userinfo/CheckJoinedMiniGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.userinfo 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.Anonymous 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class CheckJoinedMiniGallery( 11 | private val session: Session 12 | ) { 13 | data class Gallery( 14 | val title: String, 15 | val id: String, 16 | val hide: Int 17 | ) 18 | 19 | data class CheckResult( 20 | val myJoinMiniIn: List, 21 | val myJoinMiniHold: List, 22 | val myJoinMiniOut: List 23 | ) 24 | 25 | /** 26 | * 내 갤러리 정보를 받아옵니다. 27 | * 28 | * @return 내 갤러리 정보를 반환합니다. 29 | */ 30 | fun request(): CheckResult { 31 | if (session.user is Anonymous) { 32 | throw RuntimeException("Anonymous는 CheckJoinedMiniGallery을 사용할 수 없습니다.") 33 | } 34 | 35 | val option = Request.getDefaultOption() 36 | .addMultipartParameter("user_id", session.detail!!.userId) 37 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 38 | 39 | val json = JsonBrowser.parse( 40 | KotlinInside.getInstance().httpInterface.upload( 41 | ApiUrl.User.MY_MINI_JOIN_CHECK, 42 | option 43 | ) 44 | ).index(0) 45 | 46 | return CheckResult( 47 | myJoinMiniIn = mutableListOf().apply { 48 | json.get("myjoinmini_in").values().forEach { 49 | add( 50 | Gallery( 51 | title = it.get("gall_koname").safeText(), 52 | id = it.get("gall_id").safeText(), 53 | hide = it.get("gall_hide").asInteger() 54 | ) 55 | ) 56 | } 57 | }, 58 | myJoinMiniHold = mutableListOf().apply { 59 | json.get("myjoinmini_hold").values().forEach { 60 | add( 61 | Gallery( 62 | title = it.get("gall_koname").safeText(), 63 | id = it.get("gall_id").safeText(), 64 | hide = it.get("gall_hide").asInteger() 65 | ) 66 | ) 67 | } 68 | }, 69 | myJoinMiniOut = mutableListOf().apply { 70 | json.get("myjoinmini_out").values().forEach { 71 | add( 72 | Gallery( 73 | title = it.get("gall_koname").safeText(), 74 | id = it.get("gall_id").safeText(), 75 | hide = it.get("gall_hide").asInteger() 76 | ) 77 | ) 78 | } 79 | } 80 | ) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/userinfo/CheckManagedGallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.userinfo 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.Anonymous 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class CheckManagedGallery( 11 | private val session: Session 12 | ) { 13 | data class Gallery( 14 | val hide: Int, 15 | val id: String, 16 | val title: String, 17 | val type: String, // TODO: Enum class로 변경 18 | val managerType: String // TODO: Enum class로 변경 19 | ) 20 | 21 | data class CheckResult( 22 | val myManageList: List 23 | ) 24 | 25 | /** 26 | * 내 갤러리 정보를 받아옵니다. 27 | * 28 | * @return 내 갤러리 정보를 반환합니다. 29 | */ 30 | fun request(): CheckResult { 31 | if (session.user is Anonymous) { 32 | throw RuntimeException("Anonymous는 CheckJoinedMiniGallery을 사용할 수 없습니다.") 33 | } 34 | 35 | val option = Request.getDefaultOption() 36 | .addMultipartParameter("user_id", session.detail!!.userId) 37 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 38 | 39 | val json = JsonBrowser.parse( 40 | KotlinInside.getInstance().httpInterface.upload( 41 | ApiUrl.User.MY_MANAGE_GALL_CHECK, 42 | option 43 | ) 44 | ).index(0) 45 | 46 | return CheckResult( 47 | myManageList = mutableListOf().apply { 48 | json.get("mymanageList").values().forEach { 49 | add( 50 | Gallery( 51 | hide = it.get("gall_hide").asInteger(), 52 | id = it.get("gall_id").safeText(), 53 | title = it.get("gall_koname").safeText(), 54 | type = it.get("gall_type").safeText(), 55 | managerType = it.get("manager_type").safeText() 56 | ) 57 | ) 58 | } 59 | } 60 | ) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/userinfo/ModifyMyGall.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.userinfo 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.http.Request 5 | import be.zvz.kotlininside.json.JsonBrowser 6 | import be.zvz.kotlininside.session.Session 7 | import be.zvz.kotlininside.session.user.Anonymous 8 | import be.zvz.kotlininside.value.ApiUrl 9 | 10 | class ModifyMyGall( 11 | private val gallName: String, 12 | private val gallId: String, 13 | private val session: Session 14 | ) { 15 | data class ModifyMyGallResult( 16 | val result: Boolean, 17 | val cause: String 18 | ) 19 | 20 | fun request(): ModifyMyGallResult { 21 | if (session.user is Anonymous) { 22 | throw RuntimeException("Anonymous는 ModifyMyGall을 사용할 수 없습니다.") 23 | } 24 | 25 | val option = Request.getDefaultOption() 26 | .addMultipartParameter("user_id", session.detail!!.userId) 27 | .addMultipartParameter("gall_nm", gallName) 28 | .addMultipartParameter("gall_id", gallId) 29 | .addMultipartParameter("mode", "favori_gall") 30 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 31 | 32 | val json = JsonBrowser.parse( 33 | KotlinInside.getInstance().httpInterface.upload( 34 | ApiUrl.User.MY_GALL_MODIFY, 35 | option 36 | ) 37 | ).index(0) 38 | 39 | return ModifyMyGallResult( 40 | result = json.get("result").asBoolean(), 41 | cause = json.get("cause").safeText() 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/generic/userinfo/MyGall.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.generic.userinfo 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.api.type.Gallery 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | 11 | class MyGall( 12 | private val session: Session 13 | ) { 14 | data class MyGallResult( 15 | val myGall: List, 16 | val favorite: List 17 | ) 18 | 19 | /** 20 | * 내 갤러리 정보를 받아옵니다. 21 | * 22 | * @return 내 갤러리 정보를 반환합니다. 23 | */ 24 | fun request(): MyGallResult { 25 | if (session.user is Anonymous) { 26 | throw RuntimeException("Anonymous는 MyGall을 사용할 수 없습니다.") 27 | } 28 | 29 | val option = Request.getDefaultOption() 30 | .addMultipartParameter("user_id", session.detail!!.userId) 31 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 32 | 33 | val json = JsonBrowser.parse( 34 | KotlinInside.getInstance().httpInterface.upload( 35 | ApiUrl.User.MY_GALL, 36 | option 37 | ) 38 | ).index(0) 39 | 40 | return MyGallResult( 41 | myGall = mutableListOf().apply { 42 | json.get("mygall").values().forEach { 43 | add( 44 | Gallery( 45 | title = it.get("gall_koname").safeText(), 46 | id = it.get("gall_id").safeText() 47 | ) 48 | ) 49 | } 50 | }, 51 | favorite = mutableListOf().apply { 52 | json.get("favori").values().forEach { 53 | add( 54 | Gallery( 55 | title = it.get("gall_koname").safeText(), 56 | id = it.get("gall_id").safeText() 57 | ) 58 | ) 59 | } 60 | } 61 | ) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/ChangeHeadText.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.http.HttpException 6 | import be.zvz.kotlininside.http.Request 7 | import be.zvz.kotlininside.json.JsonBrowser 8 | import be.zvz.kotlininside.session.Session 9 | import be.zvz.kotlininside.session.user.Anonymous 10 | import be.zvz.kotlininside.value.ApiUrl 11 | import java.io.IOException 12 | 13 | class ChangeHeadText( 14 | private val gallId: String, 15 | private val articleId: Int, 16 | private val headTextId: Int, 17 | private val session: Session 18 | ) { 19 | data class ChangeResult( 20 | val result: Boolean, 21 | val cause: String, 22 | val state: String 23 | ) 24 | 25 | /** 26 | * 말머리 변경 요청을 전송합니다. 27 | * 28 | * @throws InsufficientPermissionException 유저 세션이 [Anonymous]일 경우, 예외를 반환합니다. 29 | * @return 변경 요청 결과 30 | */ 31 | @Throws(InsufficientPermissionException::class) 32 | fun request(): ChangeResult { 33 | val option = Request.getDefaultOption() 34 | .addMultipartParameter("id", gallId) 35 | .addMultipartParameter("no", articleId.toString()) 36 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 37 | .addMultipartParameter("mode", "headtext") 38 | .addMultipartParameter("headtxt_no", headTextId.toString()) 39 | 40 | if (session.user is Anonymous) { 41 | throw InsufficientPermissionException(ChangeHeadText::class) 42 | } else { 43 | option.addMultipartParameter("user_id", session.detail!!.userId) 44 | } 45 | 46 | val json = try { 47 | JsonBrowser.parse( 48 | KotlinInside.getInstance().httpInterface.upload( 49 | ApiUrl.Gallery.MINOR_MANAGER_REQUEST, 50 | option 51 | ) 52 | ).index(0) 53 | } catch (e: HttpException) { 54 | if (e.cause is IOException) { 55 | return ChangeResult( 56 | result = false, 57 | cause = "권한이 없습니다.", 58 | state = "" 59 | ) 60 | } else { 61 | throw e 62 | } 63 | } 64 | 65 | return ChangeResult( 66 | result = json.get("result").asBoolean(), 67 | cause = json.get("cause").safeText(), 68 | state = json.get("state").safeText() 69 | ) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/GallerySetting.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.session.Session 6 | import be.zvz.kotlininside.session.user.Anonymous 7 | import be.zvz.kotlininside.value.ApiUrl 8 | import be.zvz.kotlininside.value.Const 9 | 10 | class GallerySetting( 11 | private val gallId: String, 12 | private val session: Session 13 | ) { 14 | /** 15 | * 갤러리 관리 링크를 반환합니다. 16 | * 17 | * @throws InsufficientPermissionException 유저 세션이 [Anonymous]일 경우, 예외를 반환합니다. 18 | * @return 갤러리 관리 페이지 URL 19 | */ 20 | @Throws(InsufficientPermissionException::class) 21 | fun getLink(): String { 22 | val url = "${ApiUrl.Gallery.MINOR_MANAGEMENT}?id=$gallId&app_id=${KotlinInside.getInstance().auth.getAppId()}" 23 | 24 | if (session.user is Anonymous) { 25 | throw InsufficientPermissionException(GallerySetting::class) 26 | } else { 27 | url.plus("&confirm_id=${session.detail!!.userId}") 28 | } 29 | 30 | return url 31 | } 32 | 33 | /** 34 | * User-Agent를 반환합니다. 35 | * 36 | * @return 갤러리 관리에 접근할 때 필요한 User-Agent를 반환합니다. 37 | */ 38 | fun getUserAgent(): String { 39 | return Const.USER_AGENT 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/NoMemberBlock.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | import java.io.IOException 11 | import java.text.SimpleDateFormat 12 | import java.util.* 13 | 14 | class NoMemberBlock( 15 | private val session: Session, 16 | private val gallId: String, 17 | private val option: BlockOption = BlockOption() 18 | ) { 19 | private val dateFormat by lazy { SimpleDateFormat("yyyy.MM.dd HH:mm") } 20 | 21 | enum class ImageStatus(val value: String) { 22 | NONE(""), 23 | ANONYMOUS("A"), 24 | PROXY("P"), 25 | CELLULAR("M"), 26 | PROXY_AND_CELLULAR("P,M") 27 | } 28 | 29 | class BlockOption { 30 | val proxy: Date? = null 31 | val cellular: Date? = null 32 | val image: ImageRestrictionOption? = null 33 | 34 | class ImageRestrictionOption( 35 | val time: Date, 36 | val type: ImageStatus 37 | ) 38 | } 39 | 40 | data class BlockResult( 41 | val result: Boolean, 42 | val msg: String 43 | ) 44 | 45 | @Throws(InsufficientPermissionException::class) 46 | fun block(): BlockResult { 47 | if (session.user is Anonymous) { 48 | throw InsufficientPermissionException(NoMemberBlock::class) 49 | } else { 50 | val option = Request.getDefaultOption() 51 | .addBodyParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 52 | .addBodyParameter("confirm_id", session.detail!!.userId) 53 | .apply { 54 | // proxyDate format = 2022.02.03 20:48(yyyy.MM.dd HH:mm) 55 | // proxyDate, mobileDate, imgDate 는 현재시간 + 48시간, 현재시간 + 1시간, 현재시간 + 48시간 을 넘길 수 없습니다. 56 | // 시간을 초과하게 되면 자동으로 해제됩니다. 57 | if (option.proxy !== null) { 58 | addBodyParameter("proxyDate", dateFormat.format(option.proxy)) 59 | } 60 | if (option.cellular !== null) { 61 | addBodyParameter("mobileDate", dateFormat.format(option.cellular)) 62 | } 63 | if (option.image !== null) { 64 | addBodyParameter("imgDate", dateFormat.format(option.image.time)) 65 | if (option.image.type != ImageStatus.NONE) { 66 | addBodyParameter("imgStatus", option.image.type.value) 67 | } 68 | } 69 | } 70 | val json = try { 71 | JsonBrowser.parse( 72 | KotlinInside.getInstance().httpInterface.post( 73 | "${ApiUrl.Gallery.MINOR_NOMEMBER}/$gallId", 74 | option 75 | ) 76 | ) 77 | } catch (e: IOException) { 78 | return BlockResult( 79 | result = false, 80 | msg = "권한이 없습니다." 81 | ) 82 | } 83 | return BlockResult( 84 | result = json.get("result").asBoolean(), 85 | msg = json.get("msg").safeText() 86 | ) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/Notice.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.http.HttpException 6 | import be.zvz.kotlininside.http.Request 7 | import be.zvz.kotlininside.json.JsonBrowser 8 | import be.zvz.kotlininside.session.Session 9 | import be.zvz.kotlininside.session.user.Anonymous 10 | import be.zvz.kotlininside.value.ApiUrl 11 | import java.io.IOException 12 | 13 | class Notice( 14 | private val gallId: String, 15 | private val articleId: Int, 16 | private val session: Session 17 | ) { 18 | data class NoticeResult( 19 | val result: Boolean, 20 | val cause: String, 21 | val state: String 22 | ) 23 | 24 | /** 25 | * 공지를 설정하거나, 해제합니다. 26 | * 27 | * @throws InsufficientPermissionException 유저 세션이 [Anonymous]일 경우, 예외를 반환합니다. 28 | * @return 공지 결과 29 | */ 30 | @Throws(InsufficientPermissionException::class) 31 | fun request(): NoticeResult { 32 | val option = Request.getDefaultOption() 33 | .addMultipartParameter("id", gallId) 34 | .addMultipartParameter("no", articleId.toString()) 35 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 36 | .addMultipartParameter("mode", "notify") 37 | 38 | if (session.user is Anonymous) { 39 | throw InsufficientPermissionException(Notice::class) 40 | } else { 41 | option.addMultipartParameter("user_id", session.detail!!.userId) 42 | } 43 | 44 | val json = try { 45 | JsonBrowser.parse( 46 | KotlinInside.getInstance().httpInterface.upload( 47 | ApiUrl.Gallery.MINOR_MANAGER_REQUEST, 48 | option 49 | ) 50 | ).index(0) 51 | } catch (e: HttpException) { 52 | if (e.cause is IOException) { 53 | return NoticeResult( 54 | result = false, 55 | cause = "권한이 없습니다.", 56 | state = "" 57 | ) 58 | } else { 59 | throw e 60 | } 61 | } 62 | 63 | return NoticeResult( 64 | result = json.get("result").asBoolean(), 65 | cause = json.get("cause").safeText(), 66 | state = json.get("state").safeText() 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/Recommend.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.http.HttpException 6 | import be.zvz.kotlininside.http.Request 7 | import be.zvz.kotlininside.json.JsonBrowser 8 | import be.zvz.kotlininside.session.Session 9 | import be.zvz.kotlininside.session.user.Anonymous 10 | import be.zvz.kotlininside.value.ApiUrl 11 | import java.io.IOException 12 | 13 | class Recommend( 14 | private val gallId: String, 15 | private val articleId: Int, 16 | private val session: Session 17 | ) { 18 | data class RecommendResult( 19 | val result: Boolean, 20 | val cause: String, 21 | val state: String? = null 22 | ) 23 | 24 | /** 25 | * 개념글을 내리거나, 올립니다. 26 | * 27 | * @throws InsufficientPermissionException 유저 세션이 [Anonymous]일 경우, 예외를 반환합니다. 28 | * @return 개념글 설정 결과 29 | */ 30 | @Throws(InsufficientPermissionException::class) 31 | fun request(): RecommendResult { 32 | val option = Request.getDefaultOption() 33 | .addMultipartParameter("id", gallId) 34 | .addMultipartParameter("no", articleId.toString()) 35 | .addMultipartParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 36 | .addMultipartParameter("mode", "recommend") 37 | 38 | if (session.user is Anonymous) { 39 | throw InsufficientPermissionException(Recommend::class) 40 | } else { 41 | option.addMultipartParameter("user_id", session.detail!!.userId) 42 | } 43 | 44 | val json = try { 45 | JsonBrowser.parse( 46 | KotlinInside.getInstance().httpInterface.upload( 47 | ApiUrl.Gallery.MINOR_MANAGER_REQUEST, 48 | option 49 | ) 50 | ).index(0) 51 | } catch (e: HttpException) { 52 | if (e.cause is IOException) { 53 | return RecommendResult( 54 | result = false, 55 | cause = "권한이 없습니다." 56 | ) 57 | } else { 58 | throw e 59 | } 60 | } 61 | 62 | return RecommendResult( 63 | result = json.get("result").asBoolean(), 64 | cause = json.get("cause").safeText(), 65 | state = json.get("state").text() 66 | ) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/management/UserBlock.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.management 2 | 3 | import be.zvz.kotlininside.KotlinInside 4 | import be.zvz.kotlininside.exception.InsufficientPermissionException 5 | import be.zvz.kotlininside.http.Request 6 | import be.zvz.kotlininside.json.JsonBrowser 7 | import be.zvz.kotlininside.session.Session 8 | import be.zvz.kotlininside.session.user.Anonymous 9 | import be.zvz.kotlininside.value.ApiUrl 10 | import be.zvz.kotlininside.value.Const 11 | import java.io.IOException 12 | 13 | class UserBlock @JvmOverloads constructor( 14 | private val gallId: String, 15 | private val articleId: Int, 16 | private val session: Session, 17 | private val option: BlockOption = BlockOption() 18 | ) { 19 | enum class BlockCategory(val code: Int) { 20 | OBSCENE(1), 21 | ADVERTISEMENT(2), 22 | CUSS_WORDS(3), 23 | SPAMMING(4), 24 | PIRACY(5), 25 | DEFAMATION(6), 26 | CUSTOM(7) 27 | } 28 | 29 | class BlockOption { 30 | var commentId = 0 31 | var blockHour = 1 32 | var blockCategory = BlockCategory.CUSTOM 33 | var blockReason: String = "사유 없음" 34 | } 35 | 36 | data class BlockResult( 37 | val result: Boolean, 38 | val cause: String 39 | ) 40 | 41 | @Throws(InsufficientPermissionException::class) 42 | fun block(): BlockResult { 43 | if (session.user is Anonymous) { 44 | throw InsufficientPermissionException(UserBlock::class) 45 | } 46 | 47 | val requestOption = Request.getDefaultOption() 48 | .addBodyParameter("_token", "") 49 | .addBodyParameter("avoid_hour", option.blockHour.toString()) 50 | .addBodyParameter("avoid_category", option.blockCategory.code.toString()) 51 | 52 | if (option.blockCategory === BlockCategory.CUSTOM) { 53 | requestOption.addBodyParameter("avoid_memo", option.blockReason) 54 | } 55 | 56 | requestOption 57 | .addBodyParameter("id", gallId) 58 | .addBodyParameter("no", articleId.toString()) 59 | 60 | if (option.commentId > 0) { 61 | requestOption.addBodyParameter("comment_no", option.commentId.toString()) 62 | } 63 | 64 | requestOption 65 | .addBodyParameter("app_id", KotlinInside.getInstance().auth.getAppId()) 66 | .addBodyParameter("confirm_id", session.detail!!.userId) 67 | 68 | val json: JsonBrowser = try { 69 | JsonBrowser.parse( 70 | KotlinInside.getInstance().httpInterface.post( 71 | ApiUrl.Gallery.MINOR_BLOCK_ADD, 72 | requestOption 73 | ) 74 | ) 75 | } catch (e: IOException) { 76 | return BlockResult( 77 | result = false, 78 | cause = "권한이 없습니다." 79 | ) 80 | } 81 | 82 | return BlockResult( 83 | result = json.get("result").asBoolean(), 84 | cause = json.get("cause").safeText() 85 | ) 86 | } 87 | 88 | /** 89 | * 갤러리 유저 차단 링크를 반환합니다. 90 | * 91 | * @throws RuntimeException 유저 세션이 [Anonymous]일 경우, 예외를 반환합니다. 92 | * @return 갤러리 유저 차단 URL을 반환합니다. 93 | */ 94 | fun getLink(): String { 95 | val url = 96 | "${ApiUrl.Gallery.MINOR_BLOCK_WEB}?id=$gallId&no=$articleId&app_id=${KotlinInside.getInstance().auth.getAppId()}" 97 | 98 | if (option.commentId > 0) { 99 | url.plus("&comment_no=${option.commentId}") 100 | } 101 | 102 | if (session.user is Anonymous) { 103 | throw RuntimeException("Anonymous는 갤러리 유저 차단을 사용할 수 없습니다.") 104 | } else { 105 | url.plus("&confirm_id=${session.detail!!.userId}") 106 | } 107 | 108 | return url 109 | } 110 | 111 | /** 112 | * User-Agent를 반환합니다. 113 | * 114 | * @return 갤러리 유저 차단에 접근할 때 필요한 User-Agent를 반환합니다. 115 | */ 116 | fun getUserAgent(): String { 117 | return Const.USER_AGENT 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/Article.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type 2 | 3 | import be.zvz.kotlininside.api.type.content.Content 4 | 5 | data class Article @JvmOverloads constructor( 6 | val subject: String, 7 | val content: List, 8 | val headText: HeadText? = null 9 | ) 10 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/DCCon.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type 2 | 3 | data class DCCon @JvmOverloads constructor( 4 | val packageIndex: Int = 0, 5 | val detailIndex: Int = 0, 6 | val imgLink: String = "", 7 | val memo: String = "", 8 | val title: String = "" 9 | ) 10 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/Gallery.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type 2 | 3 | data class Gallery( 4 | val title: String, 5 | val id: String 6 | ) 7 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/HeadText.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type 2 | 3 | data class HeadText @JvmOverloads constructor( 4 | val identifier: Int, 5 | val name: String, 6 | val level: Int = 0, 7 | val selected: Boolean = false 8 | ) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/comment/Comment.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.comment 2 | 3 | interface Comment 4 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/comment/DCConComment.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.comment 2 | 3 | import be.zvz.kotlininside.api.type.DCCon 4 | 5 | data class DCConComment( 6 | val dcCon: DCCon 7 | ) : Comment 8 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/comment/StringComment.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.comment 2 | 3 | data class StringComment( 4 | val memo: String 5 | ) : Comment 6 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/Content.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | interface Content 4 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/DCConContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | import be.zvz.kotlininside.api.dccon.DCConInsert 4 | import be.zvz.kotlininside.api.type.DCCon 5 | 6 | data class DCConContent( 7 | val dcCon: DCCon, 8 | val dcConInsertResult: DCConInsert.InsertResult 9 | ) : Content 10 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/HtmlContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | data class HtmlContent( 4 | val htmlString: String 5 | ) : Content 6 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/ImageContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | import java.io.BufferedInputStream 4 | import java.io.File 5 | import java.io.FileInputStream 6 | import java.io.InputStream 7 | import java.net.URLConnection 8 | 9 | data class ImageContent @JvmOverloads constructor( 10 | val stream: InputStream, 11 | val mimeType: String? = null 12 | ) : Content, AutoCloseable { 13 | constructor( 14 | urlConnection: URLConnection 15 | ) : this( 16 | stream = BufferedInputStream(urlConnection.inputStream), 17 | mimeType = urlConnection.contentType 18 | ) 19 | constructor( 20 | file: File 21 | ) : this( 22 | stream = BufferedInputStream(FileInputStream(file)) 23 | ) 24 | 25 | override fun close() { 26 | stream.close() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/MarkdownContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | data class MarkdownContent( 4 | val markdownString: String 5 | ) : Content 6 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/MovieContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | import java.io.BufferedInputStream 4 | import java.io.File 5 | import java.io.FileInputStream 6 | import java.io.InputStream 7 | 8 | /** 9 | * [MovieContent]를 사용한 글을 작성해야 할 경우, 10 | * 글 작성 전에 [be.zvz.kotlininside.api.generic.MovieUpload]를 사용하여 11 | * [MovieContent]를 업로드 해놓아야 합니다. 12 | */ 13 | data class MovieContent @JvmOverloads constructor( 14 | val info: MovieInfo, 15 | val stream: InputStream, 16 | val mimeType: String? = null 17 | ) : Content, AutoCloseable { 18 | data class MovieInfo @JvmOverloads constructor( 19 | val allowDownload: Boolean, 20 | val description: String, 21 | val tag: List = emptyList() 22 | ) { 23 | /** 24 | * [be.zvz.kotlininside.api.generic.MovieUpload]에서 얻은 섬네일 URL 중 하나를 입력해주시면 됩니다. 25 | */ 26 | var thumbnailUrl: String = "" 27 | var width = 0 28 | internal set 29 | var height = 0 30 | internal set 31 | } 32 | 33 | internal var uploaded = false 34 | internal var fileId: Int = 0 35 | constructor( 36 | info: MovieInfo, 37 | file: File 38 | ) : this( 39 | info, 40 | stream = BufferedInputStream(FileInputStream(file)) 41 | ) 42 | 43 | override fun close() { 44 | stream.close() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/api/type/content/StringContent.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.api.type.content 2 | 3 | data class StringContent( 4 | val string: String 5 | ) : Content 6 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/exception/InsufficientPermissionException.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.exception 2 | 3 | import kotlin.reflect.KClass 4 | 5 | class InsufficientPermissionException(val causeClass: KClass<*>) : 6 | IllegalStateException("Insufficient permission to use ${causeClass.simpleName}") 7 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/http/HttpException.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.http 2 | 3 | class HttpException : RuntimeException { 4 | val statusCode: Int 5 | 6 | constructor( 7 | statusCode: Int, 8 | errorMessage: String? 9 | ) : super("Error Code : $statusCode, Error Message : $errorMessage") { 10 | this.statusCode = statusCode 11 | } 12 | 13 | constructor(cause: Throwable?) : super(cause) { 14 | statusCode = 520 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/http/Request.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.http 2 | 3 | import be.zvz.kotlininside.migbase64.Base64 4 | import be.zvz.kotlininside.value.ApiUrl 5 | import be.zvz.kotlininside.value.Const 6 | 7 | object Request { 8 | @JvmStatic 9 | fun redirectUrl(url: String): String = 10 | ApiUrl.REDIRECT + "?hash=" + Base64.encodeToString(url.toByteArray(), false) 11 | 12 | @JvmStatic 13 | fun getDefaultOption(): HttpInterface.Option = HttpInterface.Option() 14 | .setUserAgent(Const.USER_AGENT) 15 | .addHeader("Referer", "http://www.dcinside.com") 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/security/App.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.security 2 | 3 | data class App(val token: String, val id: String) 4 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/security/RandomFidGenerator.kt: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package be.zvz.kotlininside.security 15 | 16 | import be.zvz.kotlininside.migbase64.Base64 17 | import java.nio.ByteBuffer 18 | import java.util.UUID 19 | 20 | /** @hide 21 | */ 22 | object RandomFidGenerator { 23 | /** 24 | * Creates a random FID of valid format without checking if the FID is already in use by any 25 | * Firebase Installation. 26 | * 27 | * 28 | * Note: Even though this method does not check with the FIS database if the returned FID is 29 | * already in use, the probability of collision is extremely and negligibly small! 30 | * 31 | * @return random FID value 32 | */ 33 | fun createRandomFid(): String { 34 | // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 bytes. 35 | val uuidBytes = getBytesFromUUID(UUID.randomUUID(), ByteArray(17)) 36 | uuidBytes[16] = uuidBytes[0] 37 | uuidBytes[0] = (REMOVE_PREFIX_MASK.toInt() and uuidBytes[0].toInt() or FID_4BIT_PREFIX.toInt()).toByte() 38 | return encodeFidBase64UrlSafe(uuidBytes) 39 | } 40 | 41 | /** 42 | * 1 Byte with the first 4 header-bits set to the identifying FID prefix 0111 (0x7). Use this 43 | * constant to create FIDs or check the first byte of FIDs. This prefix is also used in legacy 44 | * Instance-IDs 45 | */ 46 | private val FID_4BIT_PREFIX = "01110000".toByte(2) 47 | 48 | /** 49 | * Byte mask to remove the 4 header-bits of a given Byte. Use this constant with Java's Binary AND 50 | * Operator in order to remove the first 4 bits of a Byte and replacing it with the FID prefix. 51 | */ 52 | private val REMOVE_PREFIX_MASK = "00001111".toByte(2) 53 | 54 | /** Length of new-format FIDs as introduced in 2019. */ 55 | private const val FID_LENGTH = 22 56 | 57 | /** 58 | * Converts a given byte-array (assumed to be an FID value) to base64-url-safe encoded 59 | * String-representation. 60 | * 61 | * 62 | * Note: The returned String has at most 22 characters, the length of FIDs. Thus, it is 63 | * recommended to deliver a byte-array containing at least 16.5 bytes. 64 | * 65 | * @param rawValue FID value to be encoded 66 | * @return (22-character or shorter) String containing the base64-encoded value 67 | */ 68 | private fun encodeFidBase64UrlSafe(rawValue: ByteArray): String { 69 | return Base64.encodeToString( 70 | rawValue, 71 | false 72 | ).substring(0, FID_LENGTH) 73 | } 74 | 75 | private fun getBytesFromUUID(uuid: UUID, output: ByteArray): ByteArray { 76 | val bb = ByteBuffer.wrap(output) 77 | bb.putLong(uuid.mostSignificantBits) 78 | bb.putLong(uuid.leastSignificantBits) 79 | return bb.array() 80 | } 81 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/Session.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session 2 | 3 | import be.zvz.kotlininside.session.user.User 4 | 5 | data class Session( 6 | val user: User, 7 | val detail: SessionDetail? 8 | ) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/SessionDetail.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session 2 | 3 | data class SessionDetail( 4 | val result: Boolean, 5 | val userId: String, 6 | val userNo: String, 7 | val name: String, 8 | val sessionType: String, 9 | val isAdult: Int, 10 | val isDormancy: Int, 11 | val isOtp: Int, 12 | val pwCampaign: Int, 13 | val mailSend: String, 14 | val isGonick: Int, 15 | val isSecurityCode: String, 16 | val authChange: Int, 17 | val cause: String? 18 | ) 19 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/Anonymous.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user 2 | 3 | data class Anonymous( 4 | override val id: String, 5 | override val password: String 6 | ) : User 7 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/LoginUser.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user 2 | 3 | open class LoginUser( 4 | override val id: String, 5 | override val password: String 6 | ) : User 7 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/User.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user 2 | 3 | interface User { 4 | val id: String 5 | val password: String 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/UserType.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user 2 | 3 | enum class UserType(val sessionType: String) { 4 | ANONYMOUS("C"), 5 | NAMED("A"), 6 | DUPLICATE_NAMED("B") 7 | } 8 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/named/DuplicateNamed.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user.named 2 | 3 | import be.zvz.kotlininside.session.user.LoginUser 4 | 5 | data class DuplicateNamed( 6 | override val id: String, 7 | override val password: String 8 | ) : LoginUser(id, password) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/session/user/named/Named.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.session.user.named 2 | 3 | import be.zvz.kotlininside.session.user.LoginUser 4 | 5 | data class Named( 6 | override val id: String, 7 | override val password: String 8 | ) : LoginUser(id, password) 9 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/utils/StringUtil.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.utils 2 | 3 | import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension 4 | import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension 5 | import com.vladsch.flexmark.ext.tables.TablesExtension 6 | import com.vladsch.flexmark.html.HtmlRenderer 7 | import com.vladsch.flexmark.parser.Parser 8 | import com.vladsch.flexmark.util.data.MutableDataSet 9 | 10 | object StringUtil { 11 | private val OPTIONS = MutableDataSet() 12 | .set( 13 | Parser.EXTENSIONS, 14 | listOf( 15 | TablesExtension.create(), 16 | StrikethroughExtension.create(), 17 | TaskListExtension.create() 18 | ) 19 | ) 20 | .toImmutable() 21 | 22 | private val MD_PARSER = Parser.builder(OPTIONS).build() 23 | private val HTML_RENDERER = HtmlRenderer.builder(OPTIONS).escapeHtml(true).build() 24 | 25 | @JvmStatic 26 | fun ynToBoolean(s: String): Boolean = when (s.lowercase()) { 27 | "y" -> true 28 | else -> false 29 | } 30 | 31 | @JvmStatic 32 | fun okToBoolean(s: String): Boolean = when (s.lowercase()) { 33 | "ok" -> true 34 | else -> false 35 | } 36 | 37 | @JvmStatic 38 | fun mdToHtml(s: String): String = HTML_RENDERER.render(MD_PARSER.parse(s)) 39 | 40 | @JvmStatic 41 | fun toHtml(s: String): String = StringBuilder().apply { 42 | var previousWasASpace = false 43 | 44 | s.toCharArray().forEach { c -> 45 | if (c == ' ') { 46 | if (previousWasASpace) { 47 | append(" ") 48 | previousWasASpace = false 49 | return@forEach 50 | } 51 | previousWasASpace = true 52 | } else { 53 | previousWasASpace = false 54 | } 55 | 56 | when (c) { 57 | '<' -> append("<") 58 | '>' -> append(">") 59 | '&' -> append("&") 60 | '"' -> append(""") 61 | '\n' -> append("
") 62 | '\t' -> append("     ") 63 | else -> append(c) 64 | } 65 | } 66 | }.toString() 67 | } 68 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/value/ApiUrl.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.value 2 | 3 | object ApiUrl { 4 | const val PC_WEB = Protocol.HTTPS + "gall.dcinside.com/" 5 | const val MOBILE_WEB = Protocol.HTTP + "m.dcinside.com/" 6 | const val MOBILE_WEB_HTTPS = Protocol.HTTPS + "m.dcinside.com/" 7 | const val MOBILE_APP = Protocol.HTTPS + "app.dcinside.com/" 8 | const val APP_API = MOBILE_APP + "api/" 9 | const val AUTH_API = Protocol.HTTPS + "msign.dcinside.com/" 10 | const val MAIN_API = Protocol.HTTP + "json2.dcinside.com/" 11 | const val UPLOAD = Protocol.HTTPS + "upload.dcinside.com/" 12 | const val MOVIE_UPLOAD = Protocol.HTTPS + "m4up4.dcinside.com/" 13 | const val REDIRECT = APP_API + "redirect.php" 14 | 15 | private object Protocol { 16 | const val HTTP = "http://" 17 | const val HTTPS = "https://" 18 | } 19 | 20 | object Firebase { 21 | const val INSTALLATIONS = 22 | Protocol.HTTPS + "firebaseinstallations.googleapis.com/v1/projects/dcinside-b3f40/installations" 23 | const val REMOTE_CONFIG = 24 | Protocol.HTTPS + "firebaseremoteconfig.googleapis.com/v1/projects/${Const.Register3.SENDER}/namespaces/firebase:fetch" 25 | } 26 | 27 | object PlayService { 28 | const val ANDROID_CLIENT = Protocol.HTTPS + "android.clients.google.com" 29 | const val ANDROID_APIS = Protocol.HTTPS + "android.apis.google.com" 30 | const val REGISTER3 = "$ANDROID_APIS/c2dm/register3" 31 | const val CHECKIN = "$ANDROID_CLIENT/checkin" 32 | } 33 | 34 | object Upload { 35 | const val CHECK_UPLOAD_RESTRICTION = APP_API + "chk_upload_restriction" 36 | const val MOVIE = "$MOVIE_UPLOAD/movie_upload_v1.php" 37 | } 38 | 39 | object Article { 40 | const val LIST = APP_API + "gall_list_new.php" 41 | const val READ = APP_API + "gall_view_new.php" 42 | const val WRITE = UPLOAD + "_app_write_api.php" 43 | const val DELETE = APP_API + "gall_del.php" 44 | const val MODIFY = APP_API + "gall_modify.php" 45 | const val UPVOTE = APP_API + "_recommend_up.php" 46 | const val DOWNVOTE = APP_API + "_recommend_down.php" 47 | const val REPORT = MOBILE_WEB + "api/report.php" 48 | const val HIT_UPVOTE = APP_API + "hit_recommend" 49 | const val INSERT_MOVIE_INFO = MOBILE_APP + "movie/insert-mvinfo" 50 | } 51 | 52 | object Comment { 53 | const val OK = APP_API + "comment_ok.php" 54 | const val DELETE = APP_API + "comment_del.php" 55 | const val READ = APP_API + "comment_new.php" 56 | } 57 | 58 | object DCCon { 59 | const val DCCON = APP_API + "dccon.php" 60 | } 61 | 62 | object Gallery { 63 | const val MINOR_INFO = APP_API + "minor_info" 64 | const val MINOR_MANAGEMENT = PC_WEB + "mgallery/management/mobile" 65 | const val MINOR_NOMEMBER = MOBILE_WEB_HTTPS + "management/minor/nomember" 66 | const val MINOR_MANAGER_REQUEST = APP_API + "_manager_request.php" 67 | const val MINOR_BLOCK_WEB = APP_API + "minor_avoid" 68 | const val MINOR_BLOCK_ADD = APP_API + "minor_avoidadd" 69 | } 70 | 71 | object Search { 72 | const val SEARCH = APP_API + "_total_search.php" 73 | } 74 | 75 | object Auth { 76 | const val LOGIN = AUTH_API + "api/login" 77 | const val APP_ID = AUTH_API + "auth/mobile_app_verification" 78 | const val APP_CHECK = MAIN_API + "json0/app_check_A_rina_one_new.php" 79 | } 80 | 81 | object User { 82 | const val MY_GALL = APP_API + "mygall.php" 83 | const val MY_GALL_MODIFY = APP_API + "mygall_modify.php" 84 | const val MY_MANAGE_GALL_CHECK = APP_API + "mymanageGallChk" 85 | const val MY_MINI_JOIN_CHECK = APP_API + "myminijoinGallChk" 86 | } 87 | 88 | object MiniGallery { 89 | const val JOIN = APP_API + "memberjoin" 90 | const val JOIN_OK = APP_API + "memberjoin_ok" 91 | const val QUIT = APP_API + "memberout_ok" 92 | } 93 | 94 | object MainInfo { 95 | const val NOTICE = MAIN_API + "json3/app_dc_notice_one_new.php" 96 | const val APP_MAIN = MAIN_API + "json3/main_content.php" 97 | const val GALLERY_RANKING = MAIN_API + "json3/ranking_gallery.php" 98 | const val MINOR_GALLERY_RANKING = MAIN_API + "json1/mgallmain/mgallery_ranking.php" 99 | const val MINI_GALLERY_RANKING = MAIN_API + "json1/migallmain/migallery_ranking.php" 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/kotlin/be/zvz/kotlininside/value/Const.kt: -------------------------------------------------------------------------------- 1 | package be.zvz.kotlininside.value 2 | 3 | object Const { 4 | const val DC_APP_SIGNATURE = "ReOo4u96nnv8Njd7707KpYiIVYQ3FlcKHDJE046Pg6s=" 5 | const val DC_APP_PACKAGE = "com.dcinside.app.android" 6 | const val DC_APP_VERSION_CODE = "100051" 7 | const val DC_APP_VERSION_NAME = "4.8.1" 8 | const val DC_APP_TARGET_VERSION = "33" 9 | const val USER_AGENT = "dcinside.app" 10 | 11 | object Firebase { 12 | const val APP_ID = "1:${Register3.SENDER}:android:d2ffdd960120a207727842" 13 | const val AUTH_VERSION = "FIS_v2" 14 | const val FIREBASE_CLIENT = "H4sIAAAAAAAAAKtWykhNLCpJSk0sKVayio7VUSpLLSrOzM9TslIyUqoFAFyivEQfAAAA" 15 | const val SDK_VERSION = "a:17.1.0" 16 | const val REMOTE_CONFIG_SDK_VERSION = "21.2.1" 17 | const val CERT = "43bd70dfc365ec1749f0424d28174da44ee7659d" 18 | const val OS_VERSION = "25" 19 | const val CLIV = "fcm-23.1.1" 20 | const val INFO = "Q2U3ar09NyAToOhBO1boBVw1nzmBjxg" 21 | const val TARGET_VER = DC_APP_TARGET_VERSION 22 | const val GCM_VERSION = "232512022" 23 | } 24 | 25 | object Installations { 26 | const val X_ANDROID_PACKAGE = DC_APP_PACKAGE 27 | const val X_ANDROID_CERT = Firebase.CERT 28 | const val X_GOOG_API_KEY = "AIzaSyDcbVof_4Bi2GwJ1H8NjSwSTaMPPZeCE38" 29 | } 30 | 31 | object Register3 { 32 | const val SENDER = "477369754343" 33 | const val X_SCOPE_ALL = "*" 34 | const val X_SCOPE_REFRESH_REMOTE_CONFIG = "/topics/DcRefreshRemoteConfig" 35 | const val X_SCOPE_SHOW_NOTICE_MESSAGE = "/topics/DcShowNoticeMessage" 36 | const val X_FIREBASE_APP_NAME_HASH = "R1dAH9Ui7M-ynoznwBdw01tLxhI" 37 | const val USER_AGENT = "Android-GCM/1.5 (generic_x86 KK)" 38 | const val APP = DC_APP_PACKAGE 39 | const val GCM_VERSION = Firebase.GCM_VERSION 40 | const val CERT = Firebase.CERT 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /구현 TODO.md: -------------------------------------------------------------------------------- 1 | # 구현해야하는 API 목록 2 | 3 | ### 알림 (FCM Token) 4 | - [x] 댓글 / 대댓글 알림 5 | 6 | ### 인증 7 | - [x] app_id 키젠 8 | - [ ] 캡차 9 | 10 | ### 계정 11 | - [x] 로그인 12 | - [x] 차단 확인 13 | 14 | 15 | ### 글 관련 16 | - [x] 글 조회 17 | - [x] 댓글 조회 18 | - [x] 글 목록 불러오기 19 | - [x] 사진 업로드 20 | - [x] 글 삭제 21 | - [x] 댓글 삭제 22 | - [x] 대댓글 삭제 23 | - [x] 힛갤 추천 24 | - [x] 게시물 신고 25 | 26 | **고정닉** 27 | - [x] 고닉 추천 & 비추천 28 | - [x] 고닉 글 쓰기 29 | - [x] 고닉 글 수정 30 | - [x] 고닉 댓글 작성 31 | - [x] 고닉 대댓글 작성 32 | 33 | **유동닉** 34 | - [x] 유동 추천 & 비추천 35 | - [x] 유동 글 쓰기 36 | - [x] 유동 글 수정 37 | - [x] 유동 댓글 작성 38 | - [x] 유동 대댓글 작성 39 | 40 | 41 | ### 일반 42 | - [x] 메인화면 43 | - [x] 실북갤 랭킹 44 | - [x] 마이너갤 정보 확인 45 | - [x] 마이너갤 관리자 기능 46 | 47 | **검색** 48 | - [x] 통합검색 49 | - [x] 갤러리 검색 50 | - [x] 갤러리내 글 검색 (개념글 유무 포함) 51 | 52 | **디시콘** 53 | - [x] 모든 디시콘 목록 불러오기 54 | - [x] 댓글 디시콘 사용 55 | - [x] 사용할 디시콘 목록 불러오기 56 | - [x] 다른 디시콘 정보 불러오기 57 | --------------------------------------------------------------------------------