aboutsummaryrefslogtreecommitdiff
path: root/juick-server/src/main
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2018-11-08 21:38:27 +0300
committerGravatar Vitaly Takmazov2018-11-08 21:38:27 +0300
commit7aaa3f9a29c280f01c677c918932620be45cdbd7 (patch)
tree39947b2c889afd08f9c73ba54fab91159d2af258 /juick-server/src/main
parent3ea9770d0d43fbe45449ac4531ec4b0a374d98ea (diff)
Merge everything into single Spring Boot application
Diffstat (limited to 'juick-server/src/main')
-rw-r--r--juick-server/src/main/assets/embed.js334
-rw-r--r--juick-server/src/main/assets/logo.pngbin2447 -> 0 bytes
-rw-r--r--juick-server/src/main/assets/logo@2x.pngbin4822 -> 0 bytes
-rw-r--r--juick-server/src/main/assets/scripts.js935
-rw-r--r--juick-server/src/main/assets/style.css956
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Alias.java62
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Expires.java58
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Link.java151
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Property.java75
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Signature.java21
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Subject.java62
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/Title.java68
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/XRD.java166
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/XRDConstants.java26
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/XRDException.java35
-rw-r--r--juick-server/src/main/java/com/cliqset/xrd/package-info.java33
-rw-r--r--juick-server/src/main/java/com/juick/ApiServer.java16
-rw-r--r--juick-server/src/main/java/com/juick/server/ActivityPubManager.java331
-rw-r--r--juick-server/src/main/java/com/juick/server/CommandsManager.java540
-rw-r--r--juick-server/src/main/java/com/juick/server/EmailManager.java165
-rw-r--r--juick-server/src/main/java/com/juick/server/KeystoreManager.java92
-rw-r--r--juick-server/src/main/java/com/juick/server/ServerManager.java295
-rw-r--r--juick-server/src/main/java/com/juick/server/SignatureManager.java113
-rw-r--r--juick-server/src/main/java/com/juick/server/TelegramBotManager.java412
-rw-r--r--juick-server/src/main/java/com/juick/server/TopManager.java54
-rw-r--r--juick-server/src/main/java/com/juick/server/TwitterManager.java125
-rw-r--r--juick-server/src/main/java/com/juick/server/Utils.java45
-rw-r--r--juick-server/src/main/java/com/juick/server/WebsocketManager.java174
-rw-r--r--juick-server/src/main/java/com/juick/server/XMPPConnection.java693
-rw-r--r--juick-server/src/main/java/com/juick/server/XMPPServer.java429
-rw-r--r--juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java302
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Index.java54
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Messages.java201
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Notifications.java221
-rw-r--r--juick-server/src/main/java/com/juick/server/api/PM.java116
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Post.java245
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Service.java166
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Tags.java54
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Users.java179
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/Profile.java379
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/Activity.java23
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/Context.java123
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Accept.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Announce.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Block.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Create.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Delete.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Follow.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Like.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/activities/Undo.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Image.java15
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Key.java24
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Link.java15
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Mention.java12
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Note.java64
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java25
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java58
-rw-r--r--juick-server/src/main/java/com/juick/server/api/activity/model/objects/Person.java87
-rw-r--r--juick-server/src/main/java/com/juick/server/api/apple/AppSiteAssociation.java49
-rw-r--r--juick-server/src/main/java/com/juick/server/api/hostmeta/HostMeta.java25
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/Feeds.java75
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/MessagesView.java153
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/RepliesView.java111
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModule.java33
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleGenerator.java70
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleImpl.java54
-rw-r--r--juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleParser.java42
-rw-r--r--juick-server/src/main/java/com/juick/server/api/webfinger/Resource.java51
-rw-r--r--juick-server/src/main/java/com/juick/server/api/webfinger/model/Account.java24
-rw-r--r--juick-server/src/main/java/com/juick/server/api/webfinger/model/Link.java31
-rw-r--r--juick-server/src/main/java/com/juick/server/api/webhooks/TelegramWebhook.java57
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/Info.java51
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java54
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java40
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java24
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java31
-rw-r--r--juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java31
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java22
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientErrorHandler.java35
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java76
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java63
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/SapeConfiguration.java39
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/SecurityConfig.java215
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/StorageConfiguration.java20
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/TelegramConfig.java15
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/WwwAppConfiguration.java120
-rw-r--r--juick-server/src/main/java/com/juick/server/configuration/XMPPConfig.java55
-rw-r--r--juick-server/src/main/java/com/juick/server/helpers/annotation/UserCommand.java50
-rw-r--r--juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java32
-rw-r--r--juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java33
-rw-r--r--juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java32
-rw-r--r--juick-server/src/main/java/com/juick/server/util/HttpUtils.java115
-rw-r--r--juick-server/src/main/java/com/juick/server/util/ImageUtils.java175
-rw-r--r--juick-server/src/main/java/com/juick/server/util/TagUtils.java42
-rw-r--r--juick-server/src/main/java/com/juick/server/util/UserUtils.java55
-rw-r--r--juick-server/src/main/java/com/juick/server/util/WebUtils.java62
-rw-r--r--juick-server/src/main/java/com/juick/server/www/HelpService.java69
-rw-r--r--juick-server/src/main/java/com/juick/server/www/WebApp.java71
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/AnythingFilter.java69
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/Help.java93
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/Login.java50
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/MessagesWWW.java593
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/NewMessage.java59
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/Settings.java278
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/SignUp.java172
-rw-r--r--juick-server/src/main/java/com/juick/server/www/controllers/SocialLogin.java329
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java13
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java32
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java48
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java10
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java8
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/Handshake.java39
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java202
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java57
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java57
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java95
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java13
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java10
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java73
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java220
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java88
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java68
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java40
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java158
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java231
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java16
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java189
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java65
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java28
-rw-r--r--juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java37
-rw-r--r--juick-server/src/main/java/com/juick/service/ActivityPubService.java59
-rw-r--r--juick-server/src/main/java/com/juick/service/BaseJdbcService.java41
-rw-r--r--juick-server/src/main/java/com/juick/service/CrosspostServiceImpl.java282
-rw-r--r--juick-server/src/main/java/com/juick/service/EmailServiceImpl.java108
-rw-r--r--juick-server/src/main/java/com/juick/service/ImagesServiceImpl.java82
-rw-r--r--juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java1143
-rw-r--r--juick-server/src/main/java/com/juick/service/MessengerServiceImpl.java71
-rw-r--r--juick-server/src/main/java/com/juick/service/PMQueriesServiceImpl.java149
-rw-r--r--juick-server/src/main/java/com/juick/service/PrivacyQueriesServiceImpl.java63
-rw-r--r--juick-server/src/main/java/com/juick/service/PushQueriesServiceImpl.java143
-rw-r--r--juick-server/src/main/java/com/juick/service/ShowQueriesServiceImpl.java62
-rw-r--r--juick-server/src/main/java/com/juick/service/SphinxSearchService.java97
-rw-r--r--juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java229
-rw-r--r--juick-server/src/main/java/com/juick/service/TagServiceImpl.java277
-rw-r--r--juick-server/src/main/java/com/juick/service/TelegramServiceImpl.java84
-rw-r--r--juick-server/src/main/java/com/juick/service/UserServiceImpl.java668
-rw-r--r--juick-server/src/main/java/com/juick/service/activities/ActivityListener.java19
-rw-r--r--juick-server/src/main/java/com/juick/service/activities/DeleteMessageEvent.java21
-rw-r--r--juick-server/src/main/java/com/juick/service/activities/DeleteUserEvent.java20
-rw-r--r--juick-server/src/main/java/com/juick/service/activities/FollowEvent.java21
-rw-r--r--juick-server/src/main/java/com/juick/service/activities/UndoFollowEvent.java26
-rw-r--r--juick-server/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java103
-rw-r--r--juick-server/src/main/java/com/juick/service/security/JuickUserDetailsService.java53
-rw-r--r--juick-server/src/main/java/com/juick/service/security/NullUserDetailsService.java33
-rw-r--r--juick-server/src/main/java/com/juick/service/security/deprecated/CookieSimpleHashRememberMeServices.java130
-rw-r--r--juick-server/src/main/java/com/juick/service/security/deprecated/RequestParamHashRememberMeServices.java88
-rw-r--r--juick-server/src/main/java/com/juick/service/security/entities/JuickUser.java93
-rw-r--r--juick-server/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java38
-rw-r--r--juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java65
-rw-r--r--juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java51
-rw-r--r--juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java43
-rw-r--r--juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java25
-rw-r--r--juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java57
-rw-r--r--juick-server/src/main/java/ru/sape/Sape.java23
-rw-r--r--juick-server/src/main/java/ru/sape/SapeConnection.java108
-rw-r--r--juick-server/src/main/java/ru/sape/SapePageLinks.java76
-rw-r--r--juick-server/src/main/resources/1x1.pngbin95 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/Transparent.gifbin42 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/db/migration/V1.10__favorites_user_uri.sql3
-rw-r--r--juick-server/src/main/resources/db/migration/V1.11__increase pm timestamp precision.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.12__drop unused tables.sql5
-rw-r--r--juick-server/src/main/resources/db/migration/V1.13__drop unused tables.sql5
-rw-r--r--juick-server/src/main/resources/db/migration/V1.14__drop broken pm_streams.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.15__drop unused columns add ts for some tables.sql4
-rw-r--r--juick-server/src/main/resources/db/migration/V1.16__last seen.sql2
-rw-r--r--juick-server/src/main/resources/db/migration/V1.1__Add updated_at field.sql2
-rw-r--r--juick-server/src/main/resources/db/migration/V1.2__Drop telegram_chats.sql2
-rw-r--r--juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.4__ActivityPub followers.sql7
-rw-r--r--juick-server/src/main/resources/db/migration/V1.5__Drop acct index.sql6
-rw-r--r--juick-server/src/main/resources/db/migration/V1.6__user_uri.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.7__reply_uri.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.8__html reply.sql1
-rw-r--r--juick-server/src/main/resources/db/migration/V1.9__reply_uri_index.sql1
-rw-r--r--juick-server/src/main/resources/errors.properties3
-rw-r--r--juick-server/src/main/resources/errors_ru.properties3
m---------juick-server/src/main/resources/help0
-rw-r--r--juick-server/src/main/resources/juick.pngbin4298 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/juick.sql947
-rw-r--r--juick-server/src/main/resources/messages.properties80
-rw-r--r--juick-server/src/main/resources/messages_ru.properties78
-rw-r--r--juick-server/src/main/resources/pg_schema_wip1539
-rw-r--r--juick-server/src/main/resources/rome.properties2
-rw-r--r--juick-server/src/main/resources/schema.sql396
-rw-r--r--juick-server/src/main/resources/static/favicon.pngbin244 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/static/logo.pngbin1184 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/static/tagscloud.pngbin42316 -> 0 bytes
-rw-r--r--juick-server/src/main/resources/templates/layouts/content.html38
-rw-r--r--juick-server/src/main/resources/templates/layouts/default.html16
-rw-r--r--juick-server/src/main/resources/templates/layouts/minimal.html10
-rw-r--r--juick-server/src/main/resources/templates/layouts/note.html5
-rw-r--r--juick-server/src/main/resources/templates/views/404.html11
-rw-r--r--juick-server/src/main/resources/templates/views/blog.html24
-rw-r--r--juick-server/src/main/resources/templates/views/blog_tags.html10
-rw-r--r--juick-server/src/main/resources/templates/views/help.html10
-rw-r--r--juick-server/src/main/resources/templates/views/index.html29
-rw-r--r--juick-server/src/main/resources/templates/views/login.html144
-rw-r--r--juick-server/src/main/resources/templates/views/login_success.html13
-rw-r--r--juick-server/src/main/resources/templates/views/macros/tags.html11
-rw-r--r--juick-server/src/main/resources/templates/views/partial/footer.html16
-rw-r--r--juick-server/src/main/resources/templates/views/partial/homecolumn.html25
-rw-r--r--juick-server/src/main/resources/templates/views/partial/message.html76
-rw-r--r--juick-server/src/main/resources/templates/views/partial/navigation.html36
-rw-r--r--juick-server/src/main/resources/templates/views/partial/settings_tabs.html6
-rw-r--r--juick-server/src/main/resources/templates/views/partial/tagcolumn.html33
-rw-r--r--juick-server/src/main/resources/templates/views/partial/tags.html3
-rw-r--r--juick-server/src/main/resources/templates/views/partial/usercolumn.html89
-rw-r--r--juick-server/src/main/resources/templates/views/partial/usertags.html3
-rw-r--r--juick-server/src/main/resources/templates/views/pm_inbox.html35
-rw-r--r--juick-server/src/main/resources/templates/views/pm_sent.html33
-rw-r--r--juick-server/src/main/resources/templates/views/post.html19
-rw-r--r--juick-server/src/main/resources/templates/views/post_success.html19
-rw-r--r--juick-server/src/main/resources/templates/views/settings_about.html20
-rw-r--r--juick-server/src/main/resources/templates/views/settings_auth-email.html9
-rw-r--r--juick-server/src/main/resources/templates/views/settings_main.html151
-rw-r--r--juick-server/src/main/resources/templates/views/settings_password.html17
-rw-r--r--juick-server/src/main/resources/templates/views/settings_privacy.html9
-rw-r--r--juick-server/src/main/resources/templates/views/settings_result.html9
-rw-r--r--juick-server/src/main/resources/templates/views/signup.html43
-rw-r--r--juick-server/src/main/resources/templates/views/thread.html175
-rw-r--r--juick-server/src/main/resources/templates/views/users.html17
232 files changed, 0 insertions, 23631 deletions
diff --git a/juick-server/src/main/assets/embed.js b/juick-server/src/main/assets/embed.js
deleted file mode 100644
index d4cbab8e..00000000
--- a/juick-server/src/main/assets/embed.js
+++ /dev/null
@@ -1,334 +0,0 @@
-
-function insertAfter(newNode, referenceNode) {
- referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
-}
-
-function setContent(containerNode, ...newNodes) {
- removeAllFrom(containerNode);
- newNodes.forEach(n => containerNode.appendChild(n));
- return containerNode;
-}
-
-function removeAllFrom(fromNode) {
- for (let c; c = fromNode.lastChild; ) { fromNode.removeChild(c); }
-}
-
-function htmlEscape(html) {
- let textarea = document.createElement('textarea');
- textarea.textContent = html;
- return textarea.innerHTML;
-}
-
-// rules :: [{pr: number, re: RegExp, with: string}]
-// rules :: [{pr: number, re: RegExp, with: Function}]
-// rules :: [{pr: number, re: RegExp, brackets: true, with: [string, string]}]
-// rules :: [{pr: number, re: RegExp, brackets: true, with: [string, string, Function]}]
-function formatText(txt, rules) {
- let idCounter = 0;
- function nextId() { return idCounter++; }
- function ft(txt, rules) {
- let matches = rules.map(r => { r.re.lastIndex = 0; return [r, r.re.exec(txt)]; })
- .filter(([,m]) => m !== null)
- .sort(([r1,m1],[r2,m2]) => (r1.pr - r2.pr) || (m1.index - m2.index));
- if (matches && matches.length > 0) {
- let [rule, match] = matches[0];
- let subsequentRules = rules.filter(r => r.pr >= rule.pr);
- let idStr = `<>(${nextId()})<>`;
- let outerStr = txt.substring(0, match.index) + idStr + txt.substring(rule.re.lastIndex);
- let innerStr = (rule.brackets)
- ? (() => { let [l ,r ,f] = rule.with; return l + ft((f ? f(match[1]) : match[1]), subsequentRules) + r; })()
- : match[0].replace(rule.re, rule.with);
- return ft(outerStr, subsequentRules).replace(idStr, innerStr);
- }
- return txt;
- }
- return ft(htmlEscape(txt), rules); // idStr above relies on the fact the text is escaped
-}
-
-function fixWwwLink(url) {
- return url.replace(/^(?!([a-z]+:)?\/\/)/i, '//');
-}
-
-function makeNewNode(embedType, aNode, reResult) {
- const withClasses = el => {
- if (embedType.className) {
- el.classList.add(...embedType.className.split(' '));
- }
- return el;
- };
- return embedType.makeNode(aNode, reResult, withClasses(document.createElement('div')));
-}
-
-function makeIframe(src, w, h, scrolling='no') {
- let iframe = document.createElement('iframe');
- iframe.style.width = w;
- iframe.style.height = h;
- iframe.frameBorder = 0;
- iframe.scrolling = scrolling;
- iframe.setAttribute('allowFullScreen', '');
- iframe.src = src;
- iframe.innerHTML = 'Cannot show iframes.';
- return iframe;
-}
-
-function makeResizableToRatio(element, ratio) {
- element.dataset['ratio'] = ratio;
- makeResizable(element, w => w * element.dataset['ratio']);
-}
-
-// calcHeight :: Number -> Number -- calculate element height for a given width
-function makeResizable(element, calcHeight) {
- const setHeight = el => {
- if (document.body.contains(el) && (el.offsetWidth > 0)) {
- el.style.height = (calcHeight(el.offsetWidth)).toFixed(2) + 'px';
- }
- };
- window.addEventListener('resize', () => setHeight(element));
- setHeight(element);
-}
-
-function extractDomain(url) {
- const domainRe = /^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i;
- return domainRe.exec(url)[1];
-}
-
-function urlReplace(match, p1, p2, p3) {
- let isBrackets = (p1 !== undefined);
- return (isBrackets)
- ? `<a href="${fixWwwLink(p2 || p3)}">${p1}</a>`
- : `<a href="${fixWwwLink(match)}">${extractDomain(match)}</a>`;
-}
-
-function urlReplaceInCode(match, p1, p2, p3) {
- let isBrackets = (p1 !== undefined);
- return (isBrackets)
- ? `<a href="${fixWwwLink(p2 || p3)}">${match}</a>`
- : `<a href="${fixWwwLink(match)}">${match}</a>`;
-}
-
-function messageReplyReplace(messageId) {
- return function(match, mid, rid) {
- let replyPart = (rid && rid != '0') ? '#' + rid : '';
- return `<a href="/${mid || messageId}${replyPart}">${match}</a>`;
- };
-}
-
-/**
- * Given "txt" message in unescaped plaintext with Juick markup, this function
- * returns escaped formatted HTML string.
- *
- * @param {string} txt
- * @param {string} messageId - current message id
- * @param {boolean} isCode
- * @returns {string}
- */
-function juickFormat(txt, messageId, isCode) {
- const urlRe = /(?:\[([^\]\[]+)\](?:\[([^\]]+)\]|\(((?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))\))|\b(?:[a-z]+:\/\/|www\.|ftp\.)(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[-\w+*&@#/%=~|$?!:;,.])*(?:\([-\w+*&@#/%=~|$?!:;,.]*\)|[\w+*&@#/%=~|$]))/gi;
- const bqReplace = m => m.replace(/^(?:>|&gt;)\s?/gmi, '');
- return (isCode)
- ? formatText(txt, [
- { pr: 1, re: urlRe, with: urlReplaceInCode },
- { pr: 1, re: /\B(?:#(\d+))?(?:\/(\d+))?\b/g, with: messageReplyReplace(messageId) },
- { pr: 1, re: /\B@([\w-]+)\b/gi, with: '<a href="/$1">@$1</a>' },
- ])
- : formatText(txt, [
- { pr: 0, re: /((?:^(?:>|&gt;)\s?[\s\S]+?$\n?)+)/gmi, brackets: true, with: ['<q>', '</q>', bqReplace] },
- { pr: 1, re: urlRe, with: urlReplace },
- { pr: 1, re: /\B(?:#(\d+))?(?:\/(\d+))?\b/g, with: messageReplyReplace(messageId) },
- { pr: 1, re: /\B@([\w-]+)\b/gi, with: '<a href="/$1">@$1</a>' },
- { pr: 2, re: /\B\*([^\n]+?)\*((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<b>', '</b>'] },
- { pr: 2, re: /\B\/([^\n]+?)\/((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<i>', '</i>'] },
- { pr: 2, re: /\b\_([^\n]+?)\_((?=\s)|(?=$)|(?=[!\"#$%&'*+,\-./:;<=>?@[\]^_`{|}~()]+))/g, brackets: true, with: ['<span class="u">', '</span>'] },
- { pr: 3, re: /\n/g, with: '<br/>' },
- ]);
-}
-
-function getEmbeddableLinkTypes() {
- return [
- {
- name: 'Jpeg and png images',
- id: 'embed_jpeg_and_png_images',
- className: 'picture compact',
- ctsDefault: false,
- re: /\.(jpe?g|png|svg)(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i,
- makeNode: function(aNode, reResult, div) {
- div.innerHTML = `<a href="${aNode.href}"><img src="${aNode.href}"></a>`;
- return div;
- }
- },
- {
- name: 'Gif images',
- id: 'embed_gif_images',
- className: 'picture compact',
- ctsDefault: true,
- re: /\.gif(:[a-zA-Z]+)?(?:\?[\w&;\?=]*)?$/i,
- makeNode: function(aNode, reResult, div) {
- div.innerHTML = `<a href="${aNode.href}"><img src="${aNode.href}"></a>`;
- return div;
- }
- },
- {
- name: 'Video (webm, mp4, ogv)',
- id: 'embed_webm_and_mp4_videos',
- className: 'video compact',
- ctsDefault: false,
- re: /\.(webm|mp4|m4v|ogv)(?:\?[\w&;\?=]*)?$/i,
- makeNode: function(aNode, reResult, div) {
- div.innerHTML = `<video src="${aNode.href}" title="${aNode.href}" controls></video>`;
- return div;
- }
- },
- {
- name: 'Audio (mp3, ogg, weba, opus, m4a, oga, wav)',
- id: 'embed_sound_files',
- className: 'audio singleColumn',
- ctsDefault: false,
- re: /\.(mp3|ogg|weba|opus|m4a|oga|wav)(?:\?[\w&;\?=]*)?$/i,
- makeNode: function(aNode, reResult, div) {
- div.innerHTML = `<audio src="${aNode.href}" title="${aNode.href}" controls></audio>`;
- return div;
- }
- },
- {
- name: 'YouTube videos (and playlists)',
- id: 'embed_youtube_videos',
- className: 'youtube resizableV singleColumn',
- ctsDefault: false,
- re: /^(?:https?:)?\/\/(?:www\.|m\.|gaming\.)?(?:youtu(?:(?:\.be\/|be\.com\/(?:v|embed)\/)([-\w]+)|be\.com\/watch)((?:(?:\?|&(?:amp;)?)(?:\w+=[-\.\w]*[-\w]))*)|youtube\.com\/playlist\?list=([-\w]*)(&(amp;)?[-\w\?=]*)?)/i,
- makeNode: function(aNode, reResult, div) {
- let [url, v, args, plist] = reResult;
- let iframeUrl;
- if (plist) {
- iframeUrl = '//www.youtube-nocookie.com/embed/videoseries?list=' + plist;
- } else {
- let pp = {}; args.replace(/^\?/, '')
- .split('&')
- .map(s => s.split('='))
- .forEach(z => pp[z[0]] = z[1]);
- let embedArgs = { rel: '0' };
- if (pp.t) {
- const tre = /^(?:(\d+)|(?:(\d+)h)?(?:(\d+)m)?(\d+)s|(?:(\d+)h)?(\d+)m|(\d+)h)$/i;
- let [, t, h, m, s, h1, m1, h2] = tre.exec(pp.t);
- embedArgs['start'] = (+t) || ((+(h || h1 || h2 || 0))*60*60 + (+(m || m1 || 0))*60 + (+(s || 0)));
- }
- if (pp.list) {
- embedArgs['list'] = pp.list;
- }
- v = v || pp.v;
- let argsStr = Object.keys(embedArgs)
- .map(k => `${k}=${embedArgs[k]}`)
- .join('&');
- iframeUrl = `//www.youtube-nocookie.com/embed/${v}?${argsStr}`;
- }
- let iframe = makeIframe(iframeUrl, '100%', '360px');
- iframe.onload = () => makeResizableToRatio(iframe, 9.0 / 16.0);
- return setContent(div, iframe);
- }
- },
- {
- name: 'Vimeo videos',
- id: 'embed_vimeo_videos',
- className: 'vimeo resizableV',
- ctsDefault: false,
- re: /^(?:https?:)?\/\/(?:www\.)?(?:player\.)?vimeo\.com\/(?:video\/|album\/[\d]+\/video\/)?([\d]+)/i,
- makeNode: function(aNode, reResult, div) {
- let iframe = makeIframe('//player.vimeo.com/video/' + reResult[1], '100%', '360px');
- iframe.onload = () => makeResizableToRatio(iframe, 9.0 / 16.0);
- return setContent(div, iframe);
- }
- }
- ];
-}
-
-function embedLink(aNode, linkTypes, container, afterNode) {
- let anyEmbed = false;
- let linkId = (aNode.href.replace(/^https?:/i, '').replace(/\'/gi,''));
- let sameEmbed = container.querySelector(`*[data-linkid='${linkId}']`); // do not embed the same thing twice
- if (sameEmbed === null) {
- anyEmbed = [].some.call(linkTypes, function(linkType) {
- let reResult = linkType.re.exec(aNode.href);
- if (reResult) {
- if (linkType.match && (linkType.match(aNode, reResult) === false)) { return false; }
- let newNode = makeNewNode(linkType, aNode, reResult);
- if (!newNode) { return false; }
- newNode.setAttribute('data-linkid', linkId);
- if (afterNode) {
- insertAfter(newNode, afterNode);
- } else {
- container.appendChild(newNode);
- }
- aNode.classList.add('embedLink');
- return true;
- }
- });
- }
- return anyEmbed;
-}
-
-function embedLinks(aNodes, container) {
- let anyEmbed = false;
- let embeddableLinkTypes = getEmbeddableLinkTypes();
- Array.from(aNodes).forEach(aNode => {
- let isEmbedded = embedLink(aNode, embeddableLinkTypes, container);
- anyEmbed = anyEmbed || isEmbedded;
- });
- return anyEmbed;
-}
-
-/**
- * Embed all the links inside element "x" that match to "allLinksSelector".
- * All the embedded media is placed inside "div.embedContainer".
- * "div.embedContainer" is inserted before an element matched by "beforeNodeSelector"
- * if not present. Existing container is used otherwise.
- *
- * @param {Element} x
- * @param {string} beforeNodeSelector
- * @param {string} allLinksSelector
- */
-export function embedLinksToX(x, beforeNodeSelector, allLinksSelector) {
- let isCtsPost = false;
- let allLinks = x.querySelectorAll(allLinksSelector);
-
- let existingContainer = x.querySelector('div.embedContainer');
- if (existingContainer) {
- embedLinks(allLinks, existingContainer);
- } else {
- let embedContainer = document.createElement('div');
- embedContainer.className = 'embedContainer';
-
- let anyEmbed = embedLinks(allLinks, embedContainer);
- if (anyEmbed) {
- let beforeNode = x.querySelector(beforeNodeSelector);
- x.insertBefore(embedContainer, beforeNode);
- }
- }
-}
-
-function embedLinksToArticles() {
- let beforeNodeSelector = 'nav.l';
- let allLinksSelector = 'p:not(.ir) a, pre a';
- Array.from(document.querySelectorAll('#content article')).forEach(article => {
- embedLinksToX(article, beforeNodeSelector, allLinksSelector);
- });
-}
-
-function embedLinksToPost() {
- let beforeNodeSelector = '.msg-txt + *';
- let allLinksSelector = '.msg-txt a';
- Array.from(document.querySelectorAll('#content .msg-cont')).forEach(msg => {
- embedLinksToX(msg, beforeNodeSelector, allLinksSelector);
- });
-}
-
-/**
- * Embed all the links in all messages/replies on the page.
- */
-export function embedAll() {
- if (document.querySelector('#content article[data-mid]')) {
- embedLinksToArticles();
- } else {
- embedLinksToPost();
- }
-}
-
-export const format = juickFormat;
diff --git a/juick-server/src/main/assets/logo.png b/juick-server/src/main/assets/logo.png
deleted file mode 100644
index 4e0f6d56..00000000
--- a/juick-server/src/main/assets/logo.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/assets/logo@2x.png b/juick-server/src/main/assets/logo@2x.png
deleted file mode 100644
index 6febeaf9..00000000
--- a/juick-server/src/main/assets/logo@2x.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/assets/scripts.js b/juick-server/src/main/assets/scripts.js
deleted file mode 100644
index 9ee0639e..00000000
--- a/juick-server/src/main/assets/scripts.js
+++ /dev/null
@@ -1,935 +0,0 @@
-require('element-closest');
-require('classlist.js');
-require('url-polyfill');
-require('formdata-polyfill');
-import { embedLinksToX, embedAll, format } from './embed';
-
-if (!('remove' in Element.prototype)) { // Firefox <23
- Element.prototype.remove = function() {
- if (this.parentNode) {
- this.parentNode.removeChild(this);
- }
- };
-}
-
-NodeList.prototype.forEach = Array.prototype.forEach;
-HTMLCollection.prototype.forEach = Array.prototype.forEach;
-
-NodeList.prototype.filter = Array.prototype.filter;
-HTMLCollection.prototype.filter = Array.prototype.filter;
-
-Element.prototype.selectText = function() {
- let d = document;
- if (d.body.createTextRange) {
- let range = d.body.createTextRange();
- range.moveToElementText(this);
- range.select();
- } else if (window.getSelection) {
- let selection = window.getSelection();
- let rangeSel = d.createRange();
- rangeSel.selectNodeContents(this);
- selection.removeAllRanges();
- selection.addRange(rangeSel);
- }
-};
-
-function autosize(el) {
- let offset = (!window.opera)
- ? (el.offsetHeight - el.clientHeight)
- : (el.offsetHeight + parseInt(window.getComputedStyle(el, null).getPropertyValue('border-top-width')));
-
- let resize = function(el) {
- el.style.height = 'auto';
- el.style.height = (el.scrollHeight + offset) + 'px';
- };
-
- if (el.addEventListener) {
- el.addEventListener('input', () => resize(el));
- } else if (el.attachEvent) {
- el.attachEvent('onkeyup', () => resize(el));
- }
-}
-
-function evilIcon(name) {
- return `<div class="icon icon--${name}"><svg class="icon__cnt"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#${name}-icon"></use></svg></div>`;
-}
-
-/* eslint-disable only-ascii/only-ascii */
-const translations = {
- 'en': {
- 'message.inReplyTo': 'in reply to',
- 'message.reply': 'Reply',
- 'message.likeThisMessage?': 'Recommend this message?',
- 'postForm.pleaseInputMessageText': 'Please input message text',
- 'postForm.upload': 'Upload',
- 'postForm.newMessage': 'New message...',
- 'postForm.imageLink': 'Link to image',
- 'postForm.imageFormats': 'JPG/PNG, up to 10 MB',
- 'postForm.or': 'or',
- 'postForm.tags': 'Tags (space separated)',
- 'postForm.submit': 'Send',
- 'comment.writeComment': 'Write a comment...',
- 'shareDialog.linkToMessage': 'Link to message',
- 'shareDialog.messageNumber': 'Message number',
- 'shareDialog.share': 'Share',
- 'loginDialog.pleaseIntroduceYourself': 'Please introduce yourself',
- 'loginDialog.registeredAlready': 'Registered already?',
- 'loginDialog.username': 'Username',
- 'loginDialog.password': 'Password',
- 'loginDialog.facebook': 'Login with Facebook',
- 'loginDialog.vk': 'Login with VK',
- 'loginDialog.email': 'Registration',
- 'error.error': 'Error'
- },
- 'ru': {
- 'message.inReplyTo': 'в ответ на',
- 'message.reply': 'Ответить',
- 'message.likeThisMessage?': 'Рекомендовать это сообщение?',
- 'postForm.pleaseInputMessageText': 'Пожалуйста, введите текст сообщения',
- 'postForm.upload': 'загрузить',
- 'postForm.newMessage': 'Новое сообщение...',
- 'postForm.imageLink': 'Ссылка на изображение',
- 'postForm.imageFormats': 'JPG/PNG, до 10Мб',
- 'postForm.or': 'или',
- 'postForm.tags': 'Теги (через пробел)',
- 'postForm.submit': 'Отправить',
- 'comment.writeComment': 'Написать комментарий...',
- 'shareDialog.linkToMessage': 'Ссылка на сообщение',
- 'shareDialog.messageNumber': 'Номер сообщения',
- 'shareDialog.share': 'Поделиться',
- 'loginDialog.pleaseIntroduceYourself': 'Пожалуйста, представьтесь',
- 'loginDialog.registeredAlready': 'Уже зарегистрированы?',
- 'loginDialog.username': 'Имя пользователя',
- 'loginDialog.password': 'Пароль',
- 'loginDialog.facebook': 'Войти через Facebook',
- 'loginDialog.vk': 'Войти через ВКонтакте',
- 'loginDialog.email': 'Регистрация',
- 'error.error': 'Ошибка'
- }
-};
-/* eslint-enable only-ascii/only-ascii */
-
-function getLang() {
- return (window.navigator.languages && window.navigator.languages[0])
- || window.navigator.userLanguage
- || window.navigator.language;
-}
-function i18n(key, lang = undefined) {
- const fallbackLang = 'ru';
- lang = lang || getLang().split('-')[0];
- return (translations[lang] && translations[lang][key])
- || translations[fallbackLang][key]
- || key;
-}
-
-var es, pageTitle;
-
-function initES() {
- if (!('EventSource' in window)) {
- return;
- }
- let url = '/api/events';
- let hash = document.getElementById('body').getAttribute('data-hash');
- if (hash) {
- url += '?hash=' + hash;
- }
-
- es = new EventSource(url);
- es.onopen = function() {
- console.log('online');
- if (!document.querySelector('#wsthread')) {
- var d = document.createElement('div');
- d.id = 'wsthread';
- d.addEventListener('click', nextReply);
- document.querySelector('body').appendChild(d);
- pageTitle = document.title;
- }
- };
- es.addEventListener('msg', msg => {
- try {
- var jsonMsg = JSON.parse(msg.data);
- console.log('data: ' + msg.data);
- if (jsonMsg.service) {
- return;
- }
- wsIncomingReply(jsonMsg);
- } catch (err) {
- console.log(err);
- }
- });
-}
-
-function wsIncomingReply(msg) {
- let content = document.getElementById('content');
- if (!content) { return; }
- let pageMID = content.getAttribute('data-mid');
- if (!pageMID || pageMID != msg.mid) { return; }
- let msgNum = '/' + msg.rid;
- if (msg.replyto > 0) {
- msgNum += ` ${i18n('message.inReplyTo')} <a href="#${msg.replyto}">/${msg.replyto}</a>`;
- }
- let photoDiv = (msg.attach == null) ? '' : `
- <div class="msg-media"><a href="//i.juick.com/p/${msg.mid}-${msg.rid}.${msg.attach}">
- <img src="//i.juick.com/photos-512/${msg.mid}-${msg.rid}.${msg.attach}"/></a>
- </div>`;
- let msgContHtml = `
- <div class="msg-cont">
- <div class="msg-header">
- <a href="/${msg.user.uname}/">${msg.user.uname}</a>:
- <div class="msg-avatar">
- <a href="/${msg.user.uname}/"><img src="//i.juick.com/a/${msg.user.uid}.png" alt="${msg.user.uname}"/></a>
- </div>
- <div class="msg-ts">
- <a href="/m/${msg.mid}#${msg.rid}" title="${msg.timestamp}GMT">${msg.timestamp}</a>
- </div>
- </div>
- <div class="msg-txt">${format(msg.body, msg.mid, false)}</div>${photoDiv}
- <div class="msg-links">${msgNum} &middot; <a class="msg-reply-link" href="#">${i18n('message.reply')}</a></div>
- <div class="msg-comment-target msg-comment-hidden"></div>
- </div>`;
-
- let li = document.createElement('li');
- li.setAttribute('class', 'msg reply-new');
- li.setAttribute('id', msg.rid);
- li.innerHTML = msgContHtml;
- li.addEventListener('click', newReply);
- li.addEventListener('mouseover', newReply);
- li.querySelector('a.msg-reply-link').addEventListener('click', function(e) {
- showCommentForm(msg.mid, msg.rid);
- e.preventDefault();
- });
-
- embedLinksToX(li.querySelector('.msg-cont'), '.msg-links', '.msg-txt a');
-
- document.getElementById('replies').appendChild(li);
-
- updateRepliesCounter();
-}
-
-function newReply(e) {
- var li = e.target;
- li.classList.remove('reply-new');
- li.removeEventListener('click', e);
- li.removeEventListener('mouseover', e);
- updateRepliesCounter();
-}
-
-function nextReply() {
- var li = document.querySelector('#replies>li.reply-new');
- if (li) {
- li.classList.remove('reply-new');
- li.removeEventListener('click', this);
- li.children[0].scrollIntoView();
- updateRepliesCounter();
- }
-}
-
-function updateRepliesCounter() {
- var replies = document.querySelectorAll('#replies>li.reply-new').length;
- var wsthread = document.getElementById('wsthread');
- if (replies) {
- wsthread.textContent = replies;
- wsthread.style.display = 'block';
- document.title = '[' + replies + '] ' + pageTitle;
- } else {
- wsthread.style.display = 'none';
- document.title = pageTitle;
- }
-}
-
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-
-function postformListener(formEl, ev) {
- if (ev.ctrlKey && (ev.keyCode == 10 || ev.keyCode == 13)) {
- let form = formEl.closest('form');
- if (!form.onsubmit || form.onsubmit()) {
- form.querySelector('input[type="submit"]').click();
- }
- }
-}
-function closeDialogListener(ev) {
- ev = ev || window.event;
- if (ev.keyCode == 27) {
- closeDialog();
- }
-}
-
-function newMessage(evt) {
- document.querySelectorAll('#newmessage .dialogtxt').forEach(t => {
- t.remove();
- });
- if (document.querySelector('#newmessage textarea').value.length == 0
- && document.querySelector('#newmessage .img').value.length == 0
- && !document.querySelector('#newmessage input[type="file"]')) {
- document.querySelector('#newmessage').insertAdjacentHTML('afterbegin', `<p class="dialogtxt">${i18n('postForm.pleaseInputMessageText')}</p>`);
- evt.preventDefault();
- }
-}
-
-function handleErrors(response) {
- if (!response.ok) {
- throw Error(response.statusText);
- }
- return response;
-}
-
-function showCommentForm(mid, rid) {
- let reply = document.getElementById(rid);
- let formTarget = reply.querySelector('div.msg-cont .msg-comment-target');
- if (formTarget) {
- let formHtml = `
- <form>
- <input type="hidden" name="mid" value="${mid}">
- <input type="hidden" name="rid" value="${rid}">
- <div class="msg-comment">
- <div class="ta-wrapper">
- <textarea name="body" rows="1" class="reply" placeholder="${i18n('comment.writeComment')}"></textarea>
- <div class="attach-photo">${evilIcon('ei-camera')}</div>
- </div>
- <input type="submit" value="OK">
- </div>
- </form>`;
- formTarget.insertAdjacentHTML('afterend', formHtml);
- formTarget.remove();
-
- let form = reply.querySelector('form');
- let submitButton = form.querySelector('input[type="submit"]');
-
- let attachButton = form.querySelector('.msg-comment .attach-photo');
- attachButton.addEventListener('click', e => attachCommentPhoto(e.target));
-
- let textarea = form.querySelector('.msg-comment textarea');
- textarea.addEventListener('keypress', e => postformListener(e.target, e));
- autosize(textarea);
-
- let validateMessage = () => {
- let len = textarea.value.length;
- if (len > 4096) { return 'Message is too long'; }
- return '';
- };
- form.addEventListener('submit', e => {
- let validationResult = validateMessage();
- if (validationResult) {
- e.preventDefault();
- alert(validationResult);
- return false;
- }
- submitButton.disabled = true;
- let formData = new FormData(form);
- fetch('/api/comment' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), {
- method: 'POST',
- body: formData,
- credentials: 'omit'
- }).then(handleErrors)
- .then(response => {
- if (response.ok) {
- response.json().then(result => {
- if (result.newMessage) {
- window.location.href = new URL(`${mid}#${result.newMessage.rid}`, window.location.href);
- } else {
- alert(result.text);
- }
- window.location.reload(true);
- });
- }
- }).catch(error => {
- alert(error.message);
- });
- e.preventDefault();
- });
- }
- reply.querySelector('.msg-comment textarea').focus();
-}
-
-function attachInput() {
- let inp = document.createElement('input');
- inp.setAttribute('type', 'file');
- inp.setAttribute('name', 'attach');
- inp.setAttribute('accept', 'image/jpeg,image/png');
- inp.style.visibility = 'hidden';
- return inp;
-}
-
-function attachCommentPhoto(div) {
- let input = div.querySelector('input');
- if (input) {
- input.remove();
- div.classList.remove('attach-photo-active');
- } else {
- let newInput = attachInput();
- newInput.addEventListener('change', function() {
- div.classList.add('attach-photo-active');
- });
- newInput.click();
- div.appendChild(newInput);
- }
-}
-
-function attachMessagePhoto(div) {
- var f = div.closest('form'),
- finput = f.querySelector('input[type="file"]');
- if (!finput) {
- var inp = attachInput();
- inp.style.float = 'left';
- inp.style.width = 0;
- inp.style.height = 0;
- inp.addEventListener('change', function() {
- div.textContent = i18n('postForm.upload') + ' (✓)';
- });
- f.appendChild(inp);
- inp.click();
- } else {
- finput.remove();
- div.textContent = i18n('postForm.upload');
- }
-}
-
-function showMessageLinksDialog(mid, rid) {
- let hlink = window.location.protocol + '//juick.com/' + mid;
- let mlink = '#' + mid;
- if (rid > 0) {
- hlink += '#' + rid;
- mlink += '/' + rid;
- }
- let hlinkenc = encodeURIComponent(hlink);
- let html = `
- <div class="dialogshare">
- ${i18n('shareDialog.linkToMessage')}: <div onclick="this.selectText()" class="dialogl">${hlink}</div>
- ${i18n('shareDialog.messageNumber')}: <div onclick="this.selectText()" class="dialogl">${mlink}</div>
- ${i18n('shareDialog.share')}:
- <ul>
- <li><a href="https://www.facebook.com/sharer/sharer.php?u=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-facebook')}</a></li>
- <li><a href="https://twitter.com/intent/tweet?url=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-twitter')}</a></li>
- <li><a href="https://vk.com/share.php?url=${hlinkenc}" onclick="return openSocialWindow(this)">${evilIcon('ei-sc-vk')}</a></li>
- </ul>
- </div>`;
-
- openDialog(html);
-}
-
-function showPhotoDialog(fname) {
- let width = window.innerWidth;
- let height = window.innerHeight;
- let minDimension = (width < height) ? width : height;
- if (minDimension < 640) {
- return true; // no dialog, open the link
- } else if (minDimension < 1280) {
- openDialog(`<a href="//i.juick.com/p/${fname}"><img src="//i.juick.com/photos-1024/${fname}"/></a>`, true);
- return false;
- } else {
- openDialog(`<a href="//i.juick.com/p/${fname}"><img src="//i.juick.com/p/${fname}"/></a>`, true);
- return false;
- }
-}
-
-function openPostDialog() {
- let newmessageTemplate = `
- <form id="newmessage" action="/post" method="post" enctype="multipart/form-data">
- <textarea name="body" placeholder="${i18n('postForm.newMessage')}"></textarea>
- <div>
- <input class="img" name="img" placeholder="${i18n('postForm.imageLink')} (${i18n('postForm.imageFormats')})"/>
- ${i18n('postForm.or')} <a href="#">${i18n('postForm.upload')}</a><br/>
- <input id="tags_input" class="tags" name="tags" placeholder="${i18n('postForm.tags')}"/><br/>
- <input type="submit" class="subm" value="${i18n('postForm.submit')}"/>
- </div>
- </form>
- `;
- return openDialog(newmessageTemplate);
-}
-
-function openDialog(html, image) {
- var dialogHtml = `
- <div id="dialogt">
- <div id="dialogb"></div>
- <div id="dialogw">
- <div id="dialog_header">
- <div id="dialogc">${evilIcon('ei-close')}</div>
- </div>
- ${html}
- </div>
- </div>`;
- let body = document.querySelector('body');
- body.classList.add('dialog-opened');
- body.insertAdjacentHTML('afterbegin', dialogHtml);
- if (image) {
- let header = document.querySelector('#dialog_header');
- header.classList.add('header_image');
- }
- document.addEventListener('keydown', closeDialogListener);
- document.querySelector('#dialogb').addEventListener('click', closeDialog);
- document.querySelector('#dialogc').addEventListener('click', closeDialog);
-}
-
-function closeDialog() {
- let draft = document.querySelector('#newmessage textarea');
- if (draft) {
- window.draft = draft.value;
- }
- document.querySelector('body').classList.remove('dialog-opened');
- document.querySelector('#dialogb').remove();
- document.querySelector('#dialogt').remove();
-}
-
-function openSocialWindow(a) {
- var w = window.open(a.href, 'juickshare', 'width=640,height=400');
- if (window.focus) { w.focus(); }
- return false;
-}
-
-function checkUsername() {
- var uname = document.querySelector('#username').textContent,
- style = document.querySelector('#username').style;
- fetch('/api/users?uname=' + uname)
- .then(handleErrors)
- .then(function() {
- style.background = '#FFCCCC';
- })
- .catch(function() {
- style.background = '#CCFFCC';
- });
-}
-
-/******************************************************************************/
-
-function openDialogLogin() {
- let html = `
- <div class="dialoglogin">
- <p>${i18n('loginDialog.pleaseIntroduceYourself')}:</p>
- <a href="mailto:juick@juick.com?subject=LOGIN" id="signemail">${evilIcon('ei-envelope')}${i18n('loginDialog.email')}</a>
- <a href="/_fblogin" id="signfb">${evilIcon('ei-sc-facebook')}${i18n('loginDialog.facebook')}</a>
- <a href="/_vklogin" id="signvk">${evilIcon('ei-sc-vk')}${i18n('loginDialog.vk')}</a>
- <p>${i18n('loginDialog.registeredAlready')}</p>
- <form action="/login" method="POST">
- <input class="signinput" type="text" name="username" placeholder="${i18n('loginDialog.username')}"/><br/>
- <input class="signinput" type="password" name="password" placeholder="${i18n('loginDialog.password')}"/><br/>
- <input class="signsubmit" type="submit" value="OK"/>
- </form>
- </div>`;
- openDialog(html);
- return false;
-}
-
-/******************************************************************************/
-
-function resultMessage(str) {
- var result = document.createElement('p');
- result.textContent = str;
- return result;
-}
-
-function likeMessage(e, mid) {
- if (confirm(i18n('message.likeThisMessage?'))) {
- fetch('/api/like?mid=' + mid
- + '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
- method: 'POST',
- credentials: 'omit'
- })
- .then(handleErrors)
- .then(function(response) {
- if (response.ok) {
- e.closest('article').appendChild(resultMessage('OK!'));
- }
- })
- .catch(function() {
- e.closest('article').appendChild(resultMessage(i18n('error.error')));
- });
- }
- return false;
-}
-
-function subscribeMessage(e, mid) {
- fetch('/api/subscribe?mid=' + mid
- + '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
- method: 'POST',
- credentials: 'omit'
- })
- .then(handleErrors)
- .then(function(response) {
- if (response.ok) {
- window.location.reload(true);
- } else {
- alert('Something went wrong :(');
- }
- })
- .catch(error => {
- alert(error.message);
- });
- return false;
-}
-
-/******************************************************************************/
-
-function setPopular(e, mid, popular) {
- fetch('/api/messages/set_popular?mid=' + mid
- + '&popular=' + popular
- + '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
- credentials: 'same-origin'
- })
- .then(handleErrors)
- .then(function() {
- e.closest('article').append(resultMessage('OK!'));
- });
- return false;
-}
-
-function setPrivacy(e, mid) {
- fetch('/api/messages/set_privacy?mid=' + mid
- + '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
- credentials: 'same-origin'
- })
- .then(handleErrors)
- .then(function() {
- e.closest('article').append(resultMessage('OK!'));
- });
- return false;
-}
-
-function getTags() {
- fetch('/api/tags?hash=' + document.getElementById('body').getAttribute('data-hash'), {
- credentials: 'omit'
- })
- .then(handleErrors)
- .then(response => {
- return response.json();
- })
- .then(json => {
- let tags = json.map(t => t.tag);
- let input = document.getElementById('tags_input');
- });
- return false;
-}
-
-function addTag(tag) {
- document.forms['postmsg'].body.value = '*' + tag + ' ' + document.forms['postmsg'].body.value;
- return false;
-}
-
-var users = {};
-
-function fetchUserUri(dataUri, callback) {
- if (users[dataUri]) {
- callback(users[dataUri]);
- } else {
- let data = new FormData();
- data.append('uri', dataUri);
- fetch('/u/', {
- method: 'POST',
- body: data
- }).then(handleErrors)
- .then(response => {
- return response.json();
- })
- .then(json => {
- users[dataUri] = json;
- callback(json);
- });
- }
-}
-
-/******************************************************************************/
-
-function ready(fn) {
- if (document.readyState != 'loading') {
- fn();
- } else {
- document.addEventListener('DOMContentLoaded', fn);
- }
-}
-
-ready(function() {
- document.querySelectorAll('textarea').forEach((ta) => {
- autosize(ta);
- });
-
- var insertPMButtons = function(e) {
- e.target.classList.add('narrowpm');
- e.target.parentNode.insertAdjacentHTML('afterend', '<input type="submit" value="OK"/>');
- e.target.removeEventListener('click', insertPMButtons);
- e.preventDefault();
- };
- document.querySelectorAll('textarea.replypm').forEach(function(e) {
- e.addEventListener('click', insertPMButtons);
- e.addEventListener('keypress', function(e) {
- postformListener(e.target, e);
- });
- });
- document.querySelectorAll('#postmsg textarea').forEach(function(e) {
- e.addEventListener('keypress', function(e) {
- postformListener(e.target, e);
- });
- });
-
- var content = document.getElementById('content');
- if (content) {
- var pageMID = content.getAttribute('data-mid');
- if (pageMID > 0) {
- document.querySelectorAll('li.msg').forEach(li => {
- let showReplyFormBtn = li.querySelector('.a-thread-comment');
- if (showReplyFormBtn) {
- showReplyFormBtn.addEventListener('click', function(e) {
- showCommentForm(pageMID, li.id);
- e.preventDefault();
- });
- }
- });
- let opMessage = document.querySelector('.msgthread');
- if (opMessage) {
- let replyTextarea = opMessage.querySelector('textarea.reply');
- if (replyTextarea) {
- replyTextarea.addEventListener('focus', e => showCommentForm(pageMID, 0));
- replyTextarea.addEventListener('keypress', e => postformListener(e.target, e));
- if (!window.location.hash) {
- replyTextarea.focus();
- }
- }
- }
- }
- }
-
- var postmsg = document.getElementById('postmsg');
- if (postmsg) {
- document.querySelectorAll('a').filter(t => t.href.indexOf('?') >= 0).forEach(t => {
- t.addEventListener('click', e => {
- let params = new URLSearchParams(t.href.slice(t.href.indexOf('?') + 1));
- if (params.has('tag')) {
- addTag(params.get('tag'));
- e.preventDefault();
- }
- });
- });
- postmsg.addEventListener('submit', e => {
- let formData = new FormData(postmsg);
- fetch('/api/post' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), {
- method: 'POST',
- body: formData,
- credentials: 'omit'
- }).then(handleErrors)
- .then(response => {
- if (response.ok) {
- response.json().then(result => {
- if (result.newMessage) {
- window.location = new URL(`/m/${result.newMessage.mid}`, window.location.href);
- } else {
- alert(result.text);
- }
- });
- } else {
- alert('Something went wrong :(');
- }
- }).catch(error => {
- alert(error.message);
- });
- e.preventDefault();
- });
- }
- document.querySelectorAll('.pmmsg').forEach(pmmsg => {
- pmmsg.addEventListener('submit', e => {
- let formData = new FormData(pmmsg);
- fetch('/api/pm' + '?hash=' + document.getElementById('body').getAttribute('data-hash'), {
- method: 'POST',
- body: formData,
- credentials: 'omit'
- }).then(handleErrors)
- .then(response => {
- if (response.ok) {
- response.json().then(result => {
- if (result.to) {
- window.location = new URL('/pm/sent', window.location.href);
- } else {
- alert('Something went wrong :(');
- }
- });
- } else {
- alert('Something went wrong :(');
- }
- }).catch(error => {
- alert(error.message);
- });
- e.preventDefault();
- });
- });
-
- document.querySelectorAll('.msg-menu').forEach(function(el) {
- el.addEventListener('click', function(e) {
- var reply = e.target.closest('li');
- var rid = reply ? parseInt(reply.id) : 0;
- var message = e.target.closest('section');
- var mid = message.getAttribute('data-mid') || e.target.closest('article').getAttribute('data-mid');
- showMessageLinksDialog(mid, rid);
- e.preventDefault();
- });
- });
- document.querySelectorAll('.l .a-privacy').forEach(function(e) {
- e.addEventListener('click', function(e) {
- setPrivacy(
- e.target,
- e.target.closest('article').getAttribute('data-mid'));
- e.preventDefault();
- });
- });
- document.querySelectorAll('.ir a[data-fname], .msg-media a[data-fname]').forEach(function(el) {
- el.addEventListener('click', function(e) {
- let fname = e.target.closest('[data-fname]').getAttribute('data-fname');
- if (!showPhotoDialog(fname)) {
- e.preventDefault();
- }
- });
- });
- document.querySelectorAll('.social a').forEach(function(e) {
- e.addEventListener('click', function(e) {
- openSocialWindow(e.target);
- e.preventDefault();
- });
- });
- var username = document.getElementById('username');
- if (username) {
- username.addEventListener('blur', function() {
- checkUsername();
- });
- }
-
- document.querySelectorAll('.l .a-like').forEach(function(e) {
- e.addEventListener('click', function(e) {
- likeMessage(
- e.target,
- e.target.closest('article').getAttribute('data-mid'));
- e.preventDefault();
- });
- });
- document.querySelectorAll('.l .a-sub').forEach(function(e) {
- e.addEventListener('click', function(e) {
- subscribeMessage(
- e.target,
- document.getElementById('content').getAttribute('data-mid'));
- e.preventDefault();
- });
- });
- document.querySelectorAll('.a-login').forEach(function(el) {
- el.addEventListener('click', function(e) {
- openDialogLogin();
- e.preventDefault();
- });
- });
- var unfoldall = document.getElementById('unfoldall');
- if (unfoldall) {
- unfoldall.addEventListener('click', function(e) {
- document.querySelectorAll('#replies>li').forEach(function(e) {
- e.style.display = 'block';
- });
- document.querySelectorAll('#replies .msg-comments').forEach(function(e) {
- e.style.display = 'none';
- });
- e.preventDefault();
- });
- }
- document.querySelectorAll('article').forEach(function(article) {
- if (Array.prototype.some.call(
- article.querySelectorAll('.msg-tags a'),
- function(a) {
- return a.textContent === 'NSFW';
- }
- )) {
- article.classList.add('nsfw');
- }
- });
- document.querySelectorAll('[data-uri]').forEach(el => {
- let dataUri = el.getAttribute('data-uri');
- if (dataUri) {
- setTimeout(() => fetchUserUri(dataUri, user => {
- let header = el.closest('.msg-header');
- header.querySelectorAll('.a-username').forEach(a => {
- a.setAttribute('href', user.uri);
- let img = a.querySelector('img');
- if (img && user.avatar) {
- img.setAttribute('src', user.avatar);
- img.setAttribute('alt', user.uname);
- }
- let textNode = a.childNodes[0];
- if (textNode.nodeType === Node.TEXT_NODE && textNode.nodeValue.trim().length > 0) {
- let uname = document.createTextNode(user.uname);
- a.replaceChild(uname, a.firstChild);
- }
- });
- }), 100);
- }
- });
- document.querySelectorAll('[data-user-uri]').forEach(el => {
- let dataUri = el.getAttribute('href');
- if (dataUri) {
- setTimeout(() => fetchUserUri(dataUri, user => {
- let textNode = el.childNodes[0];
- if (textNode.nodeType === Node.TEXT_NODE && textNode.nodeValue.trim().length > 0) {
- let uname = document.createTextNode(`@${user.uname}`);
- el.replaceChild(uname, el.firstChild);
- }
- }), 100);
- }
- });
- initES();
-
- embedAll();
- var elSelector = 'header',
- elClassHidden = 'header--hidden',
- elClassBackground = 'header--background',
- throttleTimeout = 500,
- element = document.querySelector(elSelector);
-
- if (element) {
-
- var dHeight = 0,
- wHeight = 0,
- wScrollCurrent = 0,
- wScrollBefore = 0,
- wScrollDiff = 0,
-
- throttle = function(delay, fn) {
- var last, deferTimer;
- return function() {
- var context = this, args = arguments, now = +new Date;
- if (last && now < last + delay) {
- clearTimeout(deferTimer);
- deferTimer = setTimeout(
- function() {
- last = now;
- fn.apply(context, args);
- },
- delay);
- } else {
- last = now;
- fn.apply(context, args);
- }
- };
- };
-
- window.addEventListener('scroll', throttle(throttleTimeout, function() {
- dHeight = document.body.offsetHeight;
- wHeight = window.innerHeight;
- wScrollCurrent = window.pageYOffset;
- wScrollDiff = wScrollBefore - wScrollCurrent;
-
- if (wScrollCurrent <= 0) {
- // scrolled to the very top; element sticks to the top
- element.classList.remove(elClassHidden);
- element.classList.remove(elClassBackground);
- } else if (wScrollDiff > 0 && element.classList.contains(elClassHidden)) {
- // scrolled up; element slides in
- element.classList.remove(elClassHidden);
- element.classList.add(elClassBackground);
- } else if (wScrollDiff < 0) {
- // scrolled down
- if (wScrollCurrent + wHeight >= dHeight && element.classList.contains(elClassHidden)) {
- // scrolled to the very bottom; element slides in
- element.classList.remove(elClassHidden);
- element.classList.add(elClassBackground);
- } else {
- // scrolled down; element slides out
- element.classList.add(elClassHidden);
- }
- }
-
- wScrollBefore = wScrollCurrent;
- }));
- }
-});
diff --git a/juick-server/src/main/assets/style.css b/juick-server/src/main/assets/style.css
deleted file mode 100644
index 02c59aad..00000000
--- a/juick-server/src/main/assets/style.css
+++ /dev/null
@@ -1,956 +0,0 @@
-/* #region generic */
-
-html,
-body,
-div,
-h1,
-h2,
-ul,
-li,
-p,
-form,
-input,
-textarea,
-pre {
- margin: 0;
- padding: 0;
-}
-textarea {
- overflow: auto;
-}
-html,
-input,
-textarea {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
- font-size: 12pt;
- -webkit-font-smoothing: subpixel-antialiased;
-}
-h1,
-h2 {
- font-weight: normal;
-}
-ul {
- list-style-type: none;
-}
-a {
- color: #069;
- text-decoration: none;
-}
-img,
-hr {
- border: none;
-}
-hr {
- background: #CCC;
- height: 1px;
- margin: 10px 0;
-}
-pre {
- background: #1e2028;
- color: #41b645;
- overflow-x: auto;
- padding: 6px 20px;
- white-space: pre;
-}
-pre::selection {
- background: #41b645;
- color: #1e2028;
-}
-pre::-moz-selection {
- background: #41b645;
- color: #1e2028;
-}
-.u {
- text-decoration: underline;
-}
-
-/* #endregion */
-
-/* #region overall layout */
-
-html {
- background: #f8f8f8;
- color: #222;
-}
-#wrapper {
- margin: 0 auto;
- width: 1000px;
- margin-top: 52px;
-}
-#column {
- float: left;
- margin-left: 10px;
- overflow: hidden;
- padding-top: 10px;
- width: 240px;
-}
-#content {
- float: right;
- margin: 12px 0 0 0;
- width: 728px;
-}
-#minimal_content {
- margin: 0 auto;
- min-width: 310px;
- width: auto;
-}
-*::selection {
- background: #006699;
- color: #fff;
-}
-body > header {
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 10;
- transition-duration: 0.5s;
- transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
- transition-property: transform;
-}
-@supports (backdrop-filter: blur(10px)) {
- body > header--background {
- background: rgba(255, 255, 255, 0.8);
- backdrop-filter: blur(10px);
- }
-}
-#header_wrapper {
- margin: 0 auto;
- width: 1000px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-wrap: wrap;
- padding: 4px;
-}
-.header--background {
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.28);
- background: #fff;
-}
-.header--hidden {
- transform: translateY(-100%);
-}
-#footer {
- clear: both;
- color: #999;
- font-size: 10pt;
- margin: 40px;
- padding: 10px 0;
-}
-
-@media screen and (max-width: 850px) {
- body {
- text-size-adjust: 100%;
- }
- body,
- #wrapper,
- #topwrapper,
- #content,
- #footer {
- float: none;
- margin: 0 auto;
- min-width: 310px;
- width: auto;
- }
- #wrapper {
- margin-top: 50px;
- }
- body > header {
- margin-bottom: 15px;
- }
- #column {
- float: none;
- margin: 0 10px;
- padding-top: 0;
- width: auto;
- }
-}
-
-/* #endregion */
-
-/* #region header internals */
-
-#logo {
- height: 36px;
- width: 110px;
-}
-#logo a {
- background: url("logo@2x.png") no-repeat;
- background-size: cover;
- border: 0;
- display: block;
- height: 36px;
- overflow: hidden;
- text-indent: 100%;
- white-space: nowrap;
- width: 110px;
-}
-#global {
- display: flex;
-}
-#global a {
- color: #888;
- display: inline-block;
- font-size: 13pt;
- padding: 14px 6px;
-}
-#global li {
- display: inline-block;
-}
-#ctitle a {
- padding: 14px;
-}
-#global li:hover,
-#ctitle a:hover,
-.l a:hover {
- background-color: #fff;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- cursor: pointer;
- transition: box-shadow 0.2s ease-in;
-}
-#search input {
- background: #FFF;
- border: 1px solid #ccc;
- outline: none !important;
- padding: 4px;
- -webkit-appearance: none;
- border-radius: 0;
-}
-
-/* #endregion */
-
-/* #region left column internals */
-
-.toolbar {
- border-top: 1px solid #CCC;
-}
-
-#column ul,
-#column p,
-#column hr {
- margin: 10px 0;
-}
-#column li > a {
- display: block;
- height: 100%;
- padding: 6px;
-}
-#column li > a:hover {
- background-color: #fff;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- transition: background-color 0.2s ease-in;
-}
-#column .margtop {
- margin-top: 15px;
-}
-
-#column .tags {
- background: #fff;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- line-height: 140%;
- padding: 6px;
- text-align: justify;
-}
-#column .inp {
- background: #fff;
- border: 1px solid #ddddd5;
- outline: none !important;
- padding: 4px;
- width: 222px;
-}
-#column .tags h4 {
- background: #eee;
- border: 1px solid #eee;
- color: #888;
- display: block;
- text-align: center;
-}
-#ctitle {
- font-size: 14pt;
-}
-#ctitle img {
- margin-right: 5px;
- vertical-align: middle;
- max-width: 48px;
- max-height: 48px;
-}
-#ustats li {
- font-size: 10pt;
- margin: 3px 0;
-}
-#column table.iread {
- width: 100%;
-}
-#column table.iread td {
- text-align: center;
-}
-#column table.iread img {
- height: 48px;
- width: 48px;
-}
-
-/* #endregion */
-
-/* #region main content */
-#content > p,
-#content > h1,
-#content > h2,
-#minimal_content > p,
-#minimal_content > h1,
-#minimal_content > h2 {
- margin: 1em 0;
-}
-.page {
- background: #eee;
- padding: 6px;
- text-align: center;
-}
-
-.page a {
- color: #888;
-}
-
-/* #endregion */
-
-/* #region article, message internals */
-
-article {
- background: #fff;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- line-height: 140%;
- margin-bottom: 10px;
- padding: 20px;
-}
-article time {
- color: #999;
- font-size: 10pt;
-}
-article p {
- clear: left;
- margin: 5px 0 15px 0;
- word-wrap: break-word;
- overflow-wrap: break-word;
-}
-article .ir {
- text-align: center;
-}
-article .ir a {
- cursor: zoom-in;
- display: block;
-}
-article .ir img {
- max-width: 100%;
-}
-article > nav.l,
-.msg-cont > nav.l {
- border-top: 1px solid #eee;
- display: flex;
- justify-content: space-around;
- font-size: 10pt;
-}
-article > nav.l a,
-.msg-cont > nav.l a {
- color: #888;
- margin-right: 15px;
-}
-article .likes {
- padding-left: 20px;
-}
-article .replies {
- margin-left: 18px;
-}
-article .tags {
- margin-top: 3px;
-}
-.msg-tags {
- margin-top: 12px;
- min-height: 1px;
-}
-article .tags > a,
-.badge,
-.msg-tags > a {
- background: #eee;
- border: 1px solid #eee;
- color: #888;
- display: inline-block;
- font-size: 10pt;
- margin-bottom: 5px;
- margin-right: 5px;
- padding: 0 10px;
-}
-.l .msg-button {
- align-items: center;
- display: flex;
- flex-basis: 0;
- flex-direction: column;
- flex-grow: 1;
- padding-top: 12px;
-}
-.l .msg-button-icon {
- font-weight: bold;
-}
-.msgthread {
- margin-bottom: 0;
-}
-.msg-avatar {
- float: left;
- max-height: 48px;
- margin-right: 10px;
- max-width: 48px;
-}
-.msg-avatar img {
- max-height: 48px;
- vertical-align: top;
- max-width: 48px;
-}
-.msg-cont {
- background: #FFF;
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
- line-height: 140%;
- margin-bottom: 12px;
- padding: 20px;
- width: 640px;
-}
-.reply-new .msg-cont {
- border-right: 5px solid #0C0;
-}
-.msg-ts {
- font-size: small;
- vertical-align: top;
-}
-.msg-ts,
-.msg-ts > a {
- color: #999;
-}
-.msg-txt {
- clear: both;
- margin: 0 0 12px;
- padding-top: 10px;
- word-wrap: break-word;
- overflow-wrap: break-word;
-}
-.msg-media {
- text-align: center;
-}
-.msg-links {
- color: #999;
- font-size: small;
- margin: 5px 0 0 0;
-}
-.msg-comments {
- color: #AAA;
- font-size: small;
- margin-top: 10px;
- overflow: hidden;
- text-indent: 10px;
-}
-.ta-wrapper {
- border: 1px solid #DDD;
- display: flex;
- flex-grow: 1;
-}
-.msg-comment {
- display: flex;
- width: 100%;
- margin-top: 10px;
-}
-.msg-comment-hidden {
- display: none;
-}
-.msg-comment textarea {
- border: 0;
- flex-grow: 1;
- outline: none !important;
- padding: 4px;
- resize: vertical;
- vertical-align: top;
-}
-.attach-photo {
- cursor: pointer;
-}
-.attach-photo-active {
- color: green;
-}
-.msg-comment input {
- align-self: flex-start;
- background: #EEE;
- border: 1px solid #CCC;
- color: #999;
- margin: 0 0 0 6px;
- position: -webkit-sticky;
- position: sticky;
- top: 70px;
- vertical-align: top;
- width: 50px;
-}
-.msg-recomms {
- color: #AAA;
- font-size: small;
- margin-top: 10px;
- overflow: hidden;
- text-indent: 10px;
-}
-#replies .msg-txt,
-#private-messages .msg-txt {
- margin: 0;
-}
-.title2 {
- background: #fff;
- margin: 20px 0;
- padding: 10px 20px;
- width: 640px;
-}
-.title2-right {
- float: right;
- line-height: 24px;
-}
-#content .title2 h2 {
- font-size: x-large;
- margin: 0;
-}
-
-@media screen and (max-width: 850px) {
- #header_wrapper {
- width: auto;
- }
- #global {
- justify-content: space-around;
- flex-grow: 1;
- }
- #search {
- padding: 4px;
- }
- article {
- overflow: auto;
- }
- article p {
- margin: 10px 0 8px 0;
- }
- .msg,
- .msg-cont {
- min-width: 280px;
- width: auto;
- }
- .msg-cont {
- margin: 8px 0;
- }
- .msg-media {
- overflow: auto;
- }
- .title2 h2 {
- font-size: large;
- }
- .msg-comment {
- flex-direction: column;
- }
- .msg-comment input {
- align-self: flex-end;
- margin: 6px 0 0 0;
- width: 100px;
- }
-}
-
-@media screen and (max-width: 480px) {
- #wrapper {
- margin-top: 104px;
- }
- #search {
- display: none;
- }
- #global a {
- padding: 14px 2px;
- font-size: 11pt;
- }
- .msg-cont > nav.l,
- article > nav.l {
- font-size: 9pt;
- }
- .msg-txt {
- padding-top: 5px;
- }
- .title2 {
- font-size: 11pt;
- width: auto;
- }
- #content .title2 h2 {
- font-size: 11pt;
- }
- .title2-right {
- line-height: initial;
- }
-}
-
-/* #endregion */
-
-/* #region user-generated texts */
-
-q:before,
-q:after {
- content: "";
-}
-q,
-blockquote {
- border-left: 3px solid #CCC;
- color: #666;
- display: block;
- margin: 10px 0 10px 10px;
- padding-left: 10px;
-}
-
-/* #endregion */
-
-/* #region new message form internals */
-
-#newmessage {
- background: #E5E5E0;
- margin-bottom: 20px;
- padding: 15px;
-}
-#newmessage textarea {
- border: 1px solid #CCC;
- box-sizing: border-box;
- margin: 0 0 5px 0;
- margin-top: 20px;
- max-height: 6em;
- min-width: 280px;
- padding: 4px;
- width: 100%;
-}
-#newmessage input {
- border: 1px solid #CCC;
- margin: 5px 0;
- padding: 2px 4px;
-}
-#newmessage .img {
- width: 500px;
-}
-#newmessage .tags {
- width: 500px;
-}
-#newmessage .subm {
- background: #EEEEE5;
- width: 150px;
-}
-@media screen and (max-width: 850px) {
- #newmessage .img,
- #newmessage .tags {
- width: 100%;
- }
-}
-
-/* #endregion */
-
-/* #region user lists */
-
-.users {
- margin: 10px 0;
- width: 100%;
- display: flex;
- flex-wrap: wrap;
-}
-.users > span {
- overflow: hidden;
- padding: 6px 0;
- width: 200px;
-}
-.users img {
- height: 32px;
- margin-right: 6px;
- vertical-align: middle;
- width: 32px;
-}
-
-/* #endregion */
-
-/* #region signup form */
-
-.signup-h1 > img {
- margin-right: 10px;
- vertical-align: middle;
-}
-.signup-h1 {
- font-size: x-large;
- margin: 20px 0 10px 0;
-}
-.signup-h2 {
- font-size: large;
- margin: 10px 0 5px 0;
-}
-.signup-hr {
- margin: 20px 0;
-}
-
-/* #endregion */
-
-/* #region PM */
-
-.newpm {
- margin: 20px 60px 30px 60px;
-}
-.newpm textarea {
- resize: vertical;
- width: 100%;
-}
-.newpm-send input {
- width: 100px;
-}
-
-/* #endregion */
-
-/* #region popup dialog (lightbox) */
-
-#dialogb {
- background: #222;
- height: 100%;
- left: 0;
- opacity: 0.6;
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 10;
-}
-#dialogt {
- height: 100%;
- left: 0;
- position: fixed;
- top: 0;
- width: 100%;
- z-index: 10;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-#dialogw {
- z-index: 11;
- max-width: 96%;
- max-height: calc(100% - 100px);
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-}
-#dialogw a {
- display: block;
-}
-#dialogw img {
- max-height: 100%;
- max-height: 90vh;
- max-width: 100%;
-}
-#dialog_header {
- width: 100%;
- height: 44px;
- position: fixed;
- display: flex;
- flex-direction: row-reverse;
- align-items: center;
-}
-.header_image {
- background: rgba(0, 0, 0, 0.28);
-}
-#dialogc {
- cursor: pointer;
- color: #ccc;
- padding-right: 6px;
-}
-.dialoglogin {
- background: #fff;
- padding: 25px;
- width: 300px;
-}
-.dialog-opened {
- overflow: hidden;
-}
-#signemail,
-#signfb,
-#signvk {
- display: block;
- line-height: 32px;
- margin: 10px 0;
- text-decoration: none;
- width: 100%;
-}
-#signvk {
- margin-bottom: 30px;
-}
-.dialoglogin form {
- margin-top: 7px;
-}
-.signinput,
-.signsubmit {
- border: 1px solid #CCC;
- margin: 3px 0;
- padding: 3px;
-}
-.signinput {
- width: 292px;
-}
-.signsubmit {
- width: 70px;
-}
-.dialogshare {
- background: #fff;
- min-width: 300px;
- overflow: auto;
- padding: 20px;
-}
-.dialogl {
- background: #fff;
- border: 1px solid #DDD;
- margin: 3px 0 20px;
- padding: 5px;
-}
-.dialogshare li {
- float: left;
- margin: 5px 10px 0 0;
-}
-.dialogshare a {
- display: block;
-}
-.dialogtxt {
- background: #fff;
- padding: 20px;
-}
-
-@media screen and (max-width: 480px) {
- .dialog-opened {
- position: fixed;
- width: 100%;
- }
-}
-
-/* #endregion */
-
-/* #region misc */
-
-#wsthread {
- background: #CCC;
- bottom: 20px;
- cursor: pointer;
- display: none;
- padding: 5px 10px;
- position: fixed;
- right: 20px;
-}
-.sharenew {
- display: inline-block;
- line-height: 32px;
- min-height: 32px;
- min-width: 200px;
- padding: 0 12px 0 37px;
-}
-.icon {
- margin-top: -2px;
- vertical-align: middle;
-}
-.icon--ei-link {
- margin-top: -1px;
-}
-.icon--ei-comment {
- margin-top: -5px;
-}
-.newmessage {
- /* textarea on the /post page */
- border: 1px solid #DDD;
- padding: 2px;
- resize: vertical;
- width: 100%;
-}
-
-/* #endregion */
-
-/* #region footer internals */
-
-#footer-social {
- float: left;
-}
-#footer-social a {
- border: 0;
- display: inline-block;
-}
-#footer-left {
- margin-left: 286px;
- margin-right: 350px;
-}
-#footer-right {
- float: right;
-}
-
-@media screen and (max-width: 850px) {
- #footer {
- margin: 0 10px;
- }
- #footer div {
- float: none;
- margin: 10px 0;
- }
-}
-
-/* #endregion */
-
-/* #region settings */
-
-fieldset {
- border: 1px dotted #ccc;
- margin-top: 25px;
-}
-
-/* #endregion */
-
-/* #region embeds */
-
-.embedContainer {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: center;
- padding: 0;
- margin: 30px -3px 15px -3px;
-}
-.embedContainer > * {
- box-sizing: border-box;
- flex-grow: 1;
- margin: 3px;
- min-width: 49%;
-}
-.embedContainer > .compact {
- flex-grow: 0;
-}
-.embedContainer .picture img {
- display: block;
-}
-.embedContainer img,
-.embedContainer video {
- max-width: 100%;
- max-height: 80vh;
-}
-.embedContainer > .audio,
-.embedContainer > .youtube {
- min-width: 90%;
-}
-.embedContainer audio {
- width: 100%;
-}
-.embedContainer iframe {
- overflow: hidden;
- resize: vertical;
- display: block;
-}
-
-/* #endregion */
-
-/* #region nsfw */
-
-article.nsfw .embedContainer img,
-article.nsfw .embedContainer video,
-article.nsfw .embedContainer iframe,
-article.nsfw .ir img {
- opacity: 0.1;
-}
-article.nsfw .embedContainer img:hover,
-article.nsfw .embedContainer video:hover,
-article.nsfw .embedContainer iframe:hover,
-article.nsfw .ir img:hover {
- opacity: 1;
-}
-
-/* #endregion */
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Alias.java b/juick-server/src/main/java/com/cliqset/xrd/Alias.java
deleted file mode 100644
index 49e4052b..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Alias.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import javax.xml.namespace.QName;
-
-@XmlType(name="Alias", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Alias {
-
- @XmlAnyAttribute()
- private Map<QName, Object> unknownAttributes;
-
- @XmlValue
- private URI value;
-
- public void setValue(URI value) {
- this.value = value;
- }
-
- public URI getValue() {
- return value;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Expires.java b/juick-server/src/main/java/com/cliqset/xrd/Expires.java
deleted file mode 100644
index b4bcdd24..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Expires.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.*;
-
-@XmlType(name="Expires", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Expires {
-
- @XmlAnyAttribute
- private Map<QName, Object> unknownAttributes;
-
- @XmlValue
- private Date value;
-
- public void setValue(Date value) {
- this.value = value;
- }
-
- public Date getValue() {
- return value;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Link.java b/juick-server/src/main/java/com/cliqset/xrd/Link.java
deleted file mode 100644
index ec8522f0..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Link.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import java.net.URI;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.XmlAnyElement;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-
-import org.w3c.dom.Element;
-
-@XmlType(name="Link", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Link {
-
- @XmlAttribute(name="rel")
- private URI rel;
-
- @XmlAttribute(name="type")
- private String type;
-
- @XmlAttribute(name="href")
- private URI href;
-
- @XmlAttribute(name="template")
- private String template;
-
- @XmlElement(name="Title")
- private List<Title> titles;
-
- @XmlElement(name="Property")
- private List<Property> properties;
-
- @XmlAnyElement
- private List<Element> unknownElements;
-
- @XmlAnyAttribute
- private Map<QName,Object> unknownAttributes;
-
- private URI processedTemplate;
-
- public void setRel(URI rel) {
- this.rel = rel;
- }
-
- public URI getRel() {
- return rel;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getType() {
- return type;
- }
-
- public void setHref(URI href) {
- this.href = href;
- }
-
- public URI getHref() {
- return href;
- }
-
- public void setTemplate(String template) {
- this.template = template;
- }
-
- public String getTemplate() {
- return template;
- }
-
- public void setTitles(List<Title> titles) {
- this.titles = titles;
- }
-
- public List<Title> getTitles() {
- return titles;
- }
-
- public void setProperties(List<Property> properties) {
- this.properties = properties;
- }
-
- public List<Property> getProperties() {
- return properties;
- }
-
- public void setUnknownElements(List<Element> unknownElements) {
- this.unknownElements = unknownElements;
- }
-
- public List<Element> getUnknownElements() {
- return unknownElements;
- }
-
- public void setUnknownAttributes(Map<QName,Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName,Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasTemplate() {
- return null != this.template;
- }
-
- public boolean hasHref() {
- return null != this.href;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-
- public void setProcessedTemplate(URI processedTemplate) {
- this.processedTemplate = processedTemplate;
- }
-
- public URI getProcessedTemplate() {
- return processedTemplate;
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Property.java b/juick-server/src/main/java/com/cliqset/xrd/Property.java
deleted file mode 100644
index 35c7d0cc..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Property.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import javax.xml.namespace.QName;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@XmlType(name="Property", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Property {
-
- @XmlAttribute(name="type", required=true)
- private URI type;
-
- @XmlAnyAttribute()
- private Map<QName, Object> unknownAttributes;
-
- @XmlValue()
- private URI value;
-
- public void setType(URI type) {
- this.type = type;
- }
-
- public URI getType() {
- return type;
- }
-
- public void setValue(URI value) {
- this.value = value;
- }
-
- public URI getValue() {
- return value;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Signature.java b/juick-server/src/main/java/com/cliqset/xrd/Signature.java
deleted file mode 100644
index f52f9218..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Signature.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-public class Signature {
-
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Subject.java b/juick-server/src/main/java/com/cliqset/xrd/Subject.java
deleted file mode 100644
index f6815317..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Subject.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyAttribute;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import javax.xml.namespace.QName;
-
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-
-@XmlType(name="Subject", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Subject {
-
- @XmlAnyAttribute()
- private Map<QName, Object> unknownAttributes;
-
- @XmlValue
- private URI value;
-
- public void setValue(URI value) {
- this.value = value;
- }
-
- public URI getValue() {
- return value;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/Title.java b/juick-server/src/main/java/com/cliqset/xrd/Title.java
deleted file mode 100644
index 7d6597bd..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/Title.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.xml.bind.annotation.*;
-import javax.xml.namespace.QName;
-
-@XmlType(name="Title", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class Title {
-
- @XmlAttribute(name="lang", namespace=XRDConstants.XML_NAMESPACE)
- private String lang;
-
- @XmlAnyAttribute()
- private Map<QName, Object> unknownAttributes;
-
- @XmlValue
- private String value;
-
- public void setValue(String value) {
- this.value = value;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setLang(String lang) {
- this.lang = lang;
- }
-
- public String getLang() {
- return lang;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- if (null == this.unknownAttributes) {
- this.unknownAttributes = new HashMap<QName, Object>();
- }
- return unknownAttributes;
- }
-
- public boolean hasUnknownAttributes() {
- return !(null == this.unknownAttributes || this.unknownAttributes.size() < 1);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/XRD.java b/juick-server/src/main/java/com/cliqset/xrd/XRD.java
deleted file mode 100644
index 393e977b..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/XRD.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-import javax.xml.namespace.QName;
-import javax.xml.bind.annotation.*;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-
-import org.w3c.dom.Element;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-
-@XmlRootElement(name="XRD", namespace=XRDConstants.XRD_NAMESPACE)
-@XmlAccessorType(XmlAccessType.FIELD)
-public class XRD {
-
- @XmlAttribute(name="id", namespace=XRDConstants.XML_NAMESPACE)
- private String id;
-
- @XmlAnyAttribute
- private Map<QName, Object> unknownAttributes;
-
- @XmlElement(name="Expires", namespace=XRDConstants.XRD_NAMESPACE)
- private Expires expires;
-
- @XmlElement(name="Subject", namespace=XRDConstants.XRD_NAMESPACE)
- private Subject subject;
-
- @XmlElement(name="Alias", namespace=XRDConstants.XRD_NAMESPACE)
- private List<Alias> aliases;
-
- @XmlElement(name="Property", namespace=XRDConstants.XRD_NAMESPACE)
- private List<Property> properties;
-
- @XmlElement(name="Link", namespace=XRDConstants.XRD_NAMESPACE)
- private List<Link> links;
-
- @XmlElement(name="Signature", namespace=XRDConstants.XML_SIG_NAMESPACE)
- private List<Signature> signatures;
-
- @XmlAnyElement
- private List<Element> unknownElements;
-
- public void setExpires(Expires expires) {
- this.expires = expires;
- }
-
- public Expires getExpires() {
- return expires;
- }
-
- public void setSubject(Subject subject) {
- this.subject = subject;
- }
-
- public Subject getSubject() {
- return subject;
- }
-
- public void setAliases(List<Alias> aliases) {
- this.aliases = aliases;
- }
-
- public List<Alias> getAliases() {
- return aliases;
- }
-
- public void setProperties(List<Property> properties) {
- this.properties = properties;
- }
-
- public List<Property> getProperties() {
- return properties;
- }
-
- public void setLinks(List<Link> links) {
- this.links = links;
- }
-
- public List<Link> getLinks() {
- return links;
- }
-
- public void setSignatures(List<Signature> signatures) {
- this.signatures = signatures;
- }
-
- public List<Signature> getSignatures() {
- return signatures;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getId() {
- return id;
- }
-
- public void setUnknownAttributes(Map<QName, Object> unknownAttributes) {
- this.unknownAttributes = unknownAttributes;
- }
-
- public Map<QName, Object> getUnknownAttributes() {
- return unknownAttributes;
- }
-
- public void setUnknownElements(List<Element> unknownElements) {
- this.unknownElements = unknownElements;
- }
-
- public List<Element> getUnknownElements() {
- return unknownElements;
- }
-
- public boolean hasId() {
- return null != this.id;
- }
-
- public boolean hasExpires() {
- return null != this.expires;
- }
-
- public boolean hasSubject() {
- return null != this.subject;
- }
-
- public boolean hasAliases() {
- return null != this.aliases;
- }
-
- public boolean hasProperties() {
- return null != this.properties;
- }
-
- public boolean hasLinks() {
- return null != this.links;
- }
-
- public static XRD fromStream(InputStream stream) throws XRDException {
- JAXBContext context;
- try {
- context = JAXBContext.newInstance(XRD.class);
- return (XRD)context.createUnmarshaller().unmarshal(stream);
- } catch (JAXBException e) {
- throw new XRDException("Unable to deserialize stream into XRD", e);
- }
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/XRDConstants.java b/juick-server/src/main/java/com/cliqset/xrd/XRDConstants.java
deleted file mode 100644
index 39e3c584..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/XRDConstants.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-public class XRDConstants {
-
- public static final String XRD_NAMESPACE = "http://docs.oasis-open.org/ns/xri/xrd-1.0";
- public static final String XML_SIG_NAMESPACE = "";
- public static final String XML_NAMESPACE = "";
-
- public static final String XRD_MEDIA_TYPE = "application/xrd+xml";
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/XRDException.java b/juick-server/src/main/java/com/cliqset/xrd/XRDException.java
deleted file mode 100644
index da1e6849..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/XRDException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- Copyright 2010 Cliqset Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package com.cliqset.xrd;
-
-@SuppressWarnings("serial")
-public class XRDException extends Exception {
-
- public XRDException() {}
-
- public XRDException(String message) {
- super(message);
- }
-
- public XRDException(Throwable cause) {
- super(cause);
- }
-
- public XRDException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/juick-server/src/main/java/com/cliqset/xrd/package-info.java b/juick-server/src/main/java/com/cliqset/xrd/package-info.java
deleted file mode 100644
index bd8f0146..00000000
--- a/juick-server/src/main/java/com/cliqset/xrd/package-info.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-@XmlSchema(
- namespace=XRD_NAMESPACE,
- elementFormDefault = XmlNsForm.QUALIFIED,
- xmlns={
- @XmlNs(prefix= StringUtils.EMPTY, namespaceURI=XRD_NAMESPACE)
- }
-)
-package com.cliqset.xrd;
-
-import org.apache.commons.lang3.StringUtils;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlNsForm;
-import javax.xml.bind.annotation.XmlSchema;
-
-import static com.cliqset.xrd.XRDConstants.XRD_NAMESPACE; \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/ApiServer.java b/juick-server/src/main/java/com/juick/ApiServer.java
deleted file mode 100644
index fb2d9701..00000000
--- a/juick-server/src/main/java/com/juick/ApiServer.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.juick;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
-import org.springframework.context.annotation.ComponentScan;
-
-@SpringBootApplication
-@EnableAutoConfiguration(exclude = { MailSenderAutoConfiguration.class })
-@ComponentScan(basePackages = {"com.juick.server", "com.juick.service"})
-public class ApiServer {
- public static void main(String[] args) {
- SpringApplication.run(ApiServer.class, args);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/ActivityPubManager.java b/juick-server/src/main/java/com/juick/server/ActivityPubManager.java
deleted file mode 100644
index 4601f7d1..00000000
--- a/juick-server/src/main/java/com/juick/server/ActivityPubManager.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.formatters.PlainTextFormatter;
-import com.juick.server.api.activity.model.Context;
-import com.juick.server.api.activity.model.activities.Accept;
-import com.juick.server.api.activity.model.activities.Announce;
-import com.juick.server.api.activity.model.activities.Create;
-import com.juick.server.api.activity.model.activities.Delete;
-import com.juick.server.api.activity.model.objects.Hashtag;
-import com.juick.server.api.activity.model.objects.Image;
-import com.juick.server.api.activity.model.objects.Mention;
-import com.juick.server.api.activity.model.objects.Note;
-import com.juick.server.api.activity.model.objects.Person;
-import com.juick.server.util.HttpUtils;
-import com.juick.service.SocialService;
-import com.juick.service.UserService;
-import com.juick.service.activities.*;
-import com.juick.service.component.*;
-import com.juick.util.MessageUtils;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-@Component
-public class ActivityPubManager implements ActivityListener, NotificationListener {
- private static final Logger logger = LoggerFactory.getLogger(ActivityPubManager.class);
- @Inject
- private SignatureManager signatureManager;
- @Inject
- private SocialService socialService;
- @Inject
- private UserService userService;
- @Inject
- private PebbleEngine pebbleEngine;
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- @Value("${service_user:juick}")
- private String serviceUsername;
-
- private User serviceUser;
-
- @PostConstruct
- public void init() {
- serviceUser = userService.getUserByName(serviceUsername);
- }
-
- @Override
- public void processFollowEvent(@Nonnull FollowEvent followEvent) {
- String acct = (String)followEvent.getRequest().getObject();
- logger.info("received follower request to {}", acct);
- User followedUser = socialService.getUserByAccountUri(acct);
- if (!followedUser.isAnonymous()) {
- // automatically accept follower requests
- Person me = (Person) signatureManager.getContext(URI.create(acct)).get();
- Person follower = (Person) signatureManager.getContext(URI.create(followEvent.getRequest().getActor())).get();
- Accept accept = new Accept();
- accept.setActor(me.getId());
- accept.setObject(followEvent.getRequest());
- try {
- signatureManager.post(me, follower, accept);
- socialService.addFollower(followedUser, follower.getId());
- logger.info("Follower added for {}", followedUser.getName());
- } catch (IOException e) {
- logger.info("activitypub exception", e);
- }
- }
- }
-
- @Override
- public void undoFollowEvent(UndoFollowEvent event) {
- String actor = event.getActor();
- String me = event.getObject();
- logger.info("{} stopping to follow {}", actor, me);
- User followedUser = socialService.getUserByAccountUri(me);
- if (!followedUser.isAnonymous()) {
- socialService.removeFollower(followedUser, actor);
- }
- }
-
- @Override
- public void deleteUserEvent(DeleteUserEvent event) {
- String acct = event.getUserUri();
- logger.info("Deleting {} from followers", acct);
- socialService.removeAccount(acct);
- }
-
- @Override
- public void deleteMessageEvent(DeleteMessageEvent event) {
- Message msg = event.getMessage();
- User user = msg.getUser();
- String userUri = personUri(user);
- Note note = makeNote(msg);
- Person me = (Person) signatureManager.getContext(URI.create(userUri)).get();
- socialService.getFollowers(user).forEach(acct -> {
- Person follower = (Person) signatureManager.getContext(URI.create(acct)).get();
- Delete delete = new Delete();
- delete.setId(note.getId());
- delete.setActor(me.getId());
- delete.setPublished(note.getPublished());
- delete.setObject(note);
- try {
- logger.info("Deletion to follower {}", follower.getId());
- signatureManager.post(me, follower, delete);
- } catch (IOException e) {
- logger.warn("activitypub exception", e);
- }
- });
- }
-
- @Override
- public void processMessageEvent(MessageEvent messageEvent) {
- Message msg = messageEvent.getMessage();
- if (MessageUtils.isPM(msg)) {
- return;
- }
- User user = msg.getUser();
- String userUri = personUri(user);
- Note note = makeNote(msg);
- Person me = (Person) signatureManager.getContext(URI.create(userUri)).get();
- Set<String> subscribers = new HashSet<>(socialService.getFollowers(user));
- if (MessageUtils.isReply(msg) && msg.getTo().getUri().toASCIIString().length() > 0) {
- String replier = msg.getTo().getUri().toASCIIString();
- subscribers.add(replier);
- List<String> cc = new ArrayList<>(note.getCc());
- cc.add(replier);
- note.setCc(cc);
- }
- subscribers.forEach(acct -> {
- Optional<Context> context = signatureManager.getContext(URI.create(acct));
- if (context.isPresent()) {
- Person follower = (Person)context.get();
- Create create = new Create();
- create.setId(note.getId());
- create.setActor(me.getId());
- create.setPublished(note.getPublished());
- create.setObject(note);
- try {
- logger.info("Posting to subscriber {}", follower.getId());
- signatureManager.post(me, follower, create);
- } catch (IOException e) {
- logger.warn("activitypub exception", e);
- }
- }
- });
- }
-
- public String inboxUri() {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath("/api/inbox").toUriString();
- }
-
- public String outboxUri(User user) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/u/%s/blog/toc", user.getName())).toUriString();
- }
-
- public String personUri(User user) {
- if (user.getUri().toString().length() > 0) {
- return user.getUri().toASCIIString();
- }
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/u/%s", user.getName())).toUriString();
- }
- public String personWebUri(User user) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/%s/", user.getName())).toUriString();
- }
-
- public String followersUri(User user) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/u/%s/followers/toc", user.getName())).toUriString();
- }
-
- public String followingUri(User user) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/u/%s/following/toc", user.getName())).toUriString();
- }
- public String messageUri(Message msg) {
- return messageUri(msg.getMid(), msg.getRid());
- }
- public String messageUri(int mid, int rid) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- uri.replacePath(String.format("/n/%d-%d", mid, rid));
- return uri.toUriString();
- }
- public String tagUri(com.juick.Tag tag) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- return uri.replacePath(String.format("/t/%s", tag.getName())).toUriString();
- }
-
- public Note makeNote(Message msg) {
- Note note = new Note();
- note.setId(messageUri(msg));
- note.setUrl(PlainTextFormatter.formatUrl(msg));
- note.setAttributedTo(personUri(msg.getUser()));
- if (MessageUtils.isReply(msg)) {
- if (msg.getReplyToUri().toASCIIString().length() > 0) {
- note.setInReplyTo(msg.getReplyToUri().toASCIIString());
- } else {
- note.setInReplyTo(messageUri(msg.getMid(), msg.getReplyto()));
- }
- }
- if (MessageUtils.isPM(msg)) {
- note.setTo(Collections.singletonList(personUri(msg.getTo())));
- } else {
- note.setTo(Collections.singletonList("https://www.w3.org/ns/activitystreams#Public"));
- note.setCc(Collections.singletonList(followersUri(msg.getUser())));
- }
- note.setPublished(msg.getTimestamp());
- if (StringUtils.isNotBlank(msg.getAttachmentType())) {
- Image attachment = new Image();
- attachment.setId(msg.getAttachment().getMedium().getUrl());
- attachment.setUrl(msg.getAttachment().getMedium().getUrl());
- attachment.setMediaType(HttpUtils.mediaType(msg.getAttachmentType()));
- note.setAttachment(Collections.singletonList(attachment));
- }
- note.setTags(msg.getTags().stream().map(t -> {
- Hashtag hashtag = new Hashtag();
- hashtag.setId(tagUri(t));
- hashtag.setName(t.getName());
- return hashtag;
- }).collect(Collectors.toList()));
- if (msg.getReplyToUri() != null && msg.getReplyToUri().toASCIIString().length() > 0) {
- Optional<Context> noteContext = signatureManager.getContext(msg.getReplyToUri());
- if (noteContext.isPresent()) {
- Note activity = (Note) noteContext.get();
- Optional<Context> personContext = signatureManager.getContext(URI.create(activity.getAttributedTo()));
- if (personContext.isPresent()) {
- Person person = (Person) personContext.get();
- note.getTags().add(new Mention(person.getUrl(), person.getPreferredUsername()));
- msg.getTo().setName(person.getPreferredUsername());
- note.setInReplyTo(activity.getInReplyTo());
- }
- }
- } else if (MessageUtils.isReply(msg)) {
- note.getTags().add(new Mention(personWebUri(msg.getTo()), msg.getTo().getName()));
- }
- MessageUtils.getGlobalMentions(msg).forEach(m -> {
- // @user@server.tld -> user@server.tld
- Optional<Context> personContext = signatureManager.discoverPerson(m.substring(1));
- if (personContext.isPresent()) {
- Person person = (Person) personContext.get();
- note.getTags().add(new Mention(person.getUrl(), person.getPreferredUsername()));
- List<String> cc = new ArrayList<>(note.getCc());
- cc.add(person.getUrl());
- note.setCc(cc);
- }
- });
- if (msg.isHtml()) {
- note.setContent(msg.getText());
- } else {
- PebbleTemplate noteTemplate = pebbleEngine.getTemplate("layouts/note");
- Map<String, Object> context = new HashMap<>();
- context.put("msg", msg);
- context.put("baseUri", baseUri);
- try {
- Writer writer = new StringWriter();
- noteTemplate.evaluate(writer, context);
- note.setContent(writer.toString());
- } catch (IOException e) {
- logger.warn("template not rendered, falling back");
- note.setContent(MessageUtils.formatMessage(StringUtils.defaultString(msg.getText())));
- }
- }
- return note;
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
-
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
-
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
- Message message = topEvent.getMessage();
- Note note = makeNote(message);
- Announce announce = new Announce();
- announce.setId(note.getId() + "#top");
- announce.setActor(personUri(serviceUser));
- announce.setObject(note);
- Person me = (Person) signatureManager.getContext(URI.create(announce.getActor())).get();
- socialService.getFollowers(serviceUser).forEach(acct -> {
- Person follower = (Person) signatureManager.getContext(URI.create(acct)).get();
- try {
- logger.info("Announcing top: {}", message.getMid());
- signatureManager.post(me, follower, announce);
- } catch (IOException e) {
- logger.warn("activitypub exception", e);
- }
- });
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/CommandsManager.java b/juick-server/src/main/java/com/juick/server/CommandsManager.java
deleted file mode 100644
index 82143482..00000000
--- a/juick-server/src/main/java/com/juick/server/CommandsManager.java
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.formatters.PlainTextFormatter;
-import com.juick.service.activities.DeleteMessageEvent;
-import com.juick.service.component.*;
-import com.juick.model.CommandResult;
-import com.juick.model.TagStats;
-import com.juick.server.helpers.annotation.UserCommand;
-import com.juick.server.util.HttpUtils;
-import com.juick.service.*;
-import com.juick.util.MessageUtils;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.commons.lang3.reflect.MethodUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-/**
- *
- * @author ugnich
- */
-@Component
-public class CommandsManager {
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private ShowQueriesService showQueriesService;
- @Inject
- private PrivacyQueriesService privacyQueriesService;
- @Inject
- private SubscriptionService subscriptionService;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Inject
- private ImagesService imagesService;
-
- public CommandResult processCommand(User user, String data, @Nonnull URI attachment) throws Exception {
- if (!user.isAnonymous()) {
- userService.updateLastSeen(user);
- }
- String strippedData = StringUtils.stripStart(data, null);
- if (strippedData.startsWith("?OTR")) {
- return CommandResult.fromString("?OTR Error: we are not using OTR");
- }
- String input = MessageUtils.stripNonSafeUrls(strippedData);
- Optional<Method> cmd = MethodUtils.getMethodsListWithAnnotation(getClass(), UserCommand.class).stream()
- .filter(m -> Pattern.compile(m.getAnnotation(UserCommand.class).pattern(),
- m.getAnnotation(UserCommand.class).patternFlags()).matcher(input).matches())
- .findFirst();
- if (cmd.isPresent()) {
- Matcher matcher = Pattern.compile(cmd.get().getAnnotation(UserCommand.class).pattern(),
- cmd.get().getAnnotation(UserCommand.class).patternFlags()).matcher(input);
- List<String> groups = new ArrayList<>();
- while (matcher.find()) {
- for (int i = 1; i <= matcher.groupCount(); i++) {
- groups.add(matcher.group(i));
- }
- }
- CommandResult commandResult = (CommandResult) getClass().getMethod(cmd.get().getName(), User.class, URI.class, String[].class)
- .invoke(this, user, attachment, groups.toArray(new String[groups.size()]));
- if (StringUtils.isNotEmpty(commandResult.getText())) {
- return commandResult;
- }
- }
- Pair<String, List<Tag>> tags = tagService.fromString(input);
- if (tags.getRight().size() > 5) {
- return CommandResult.fromString("Sorry, 5 tags maximum.");
- }
- // new message
- String body = tags.getLeft().trim();
- boolean haveAttachment = StringUtils.isNotEmpty(attachment.toString());
- String attachmentFName = null;
- String attachmentType = null;
- if (haveAttachment) {
- attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost()
- : HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost();
- attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
- }
- int mid = messagesService.createMessage(user.getUid(), body, attachmentType, tags.getRight());
- if (haveAttachment) {
- String fname = String.format("%d.%s", mid, attachmentType);
- imagesService.saveImageWithPreviews(attachmentFName, fname);
- }
- Message msg = messagesService.getMessage(mid);
- subscriptionService.subscribeMessage(msg, user);
-
- applicationEventPublisher.publishEvent(new MessageReadEvent(this, user, msg));
- applicationEventPublisher.publishEvent(new MessageEvent(this, msg, subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg)));
- return CommandResult.build(msg, "New message posted.\n#" + msg.getMid() + " https://juick.com/m/" + msg.getMid(), String.format("[New message](%s) posted", PlainTextFormatter.formatUrl(msg)));
- }
-
- @UserCommand(pattern = "^ping$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "PING - returns you a PONG")
- public CommandResult commandPing(User user, URI attachment, String[] input) {
- applicationEventPublisher.publishEvent(new PingEvent(this, user));
- return CommandResult.fromString("PONG");
- }
-
- @UserCommand(pattern = "^help$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "HELP - returns this help message")
- public CommandResult commandHelp(User user, URI attachment, String[] input) {
- return CommandResult.fromString(Arrays.stream(getClass().getDeclaredMethods())
- .filter(m -> m.isAnnotationPresent(UserCommand.class))
- .map(m -> m.getAnnotation(UserCommand.class).help())
- .collect(Collectors.joining("\n")));
- }
-
- @UserCommand(pattern = "^login$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "LOGIN - log in to Juick website")
- public CommandResult commandLogin(User user_from, URI attachment, String[] input) {
- return CommandResult.fromString("http://juick.com/login?hash=" + userService.getHashByUID(user_from.getUid()));
- }
- @UserCommand(pattern = "^\\@(\\S+)\\s+([\\s\\S]+)$", help = "@username message - send PM to username")
- public CommandResult commandPM(User user_from, URI attachment, String... arguments) {
- String body = arguments[1];
-
- User user_to = userService.getUserByName(arguments[0]);
-
- if (!user_to.isAnonymous()) {
- if (!userService.isInBLAny(user_to.getUid(), user_from.getUid())) {
- if (pmQueriesService.createPM(user_from.getUid(), user_to.getUid(), body)) {
- com.juick.Message jmsg = new com.juick.Message();
- jmsg.setUser(user_from);
- jmsg.setTo(user_to);
- jmsg.setText(body);
- applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg, Collections.singletonList(user_to)));
- return CommandResult.fromString("Private message sent");
- }
- }
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^bl$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL - Show your blacklist")
- public CommandResult commandBLShow(User user_from, URI attachment, String... arguments) {
- List<User> blusers = userService.getUserBLUsers(user_from.getUid());
- List<String> bltags = tagService.getUserBLTags(user_from.getUid());
-
- String txt = StringUtils.EMPTY;
- if (bltags.size() > 0) {
- for (String bltag : bltags) {
- txt += "*" + bltag + "\n";
- }
-
- if (blusers.size() > 0) {
- txt += "\n";
- }
- }
- if (blusers.size() > 0) {
- for (User bluser : blusers) {
- txt += "@" + bluser.getName() + "\n";
- }
- }
- if (txt.isEmpty()) {
- txt = "You don't have any users or tags in your blacklist.";
- }
-
- return CommandResult.fromString(txt);
- }
-
- @UserCommand(pattern = "^#\\+$", help = "#+ - Show last Juick messages")
- public CommandResult commandLast(User user_from, URI attachment, String... arguments) {
- return CommandResult.fromString("Last messages:\n"
- + printMessages(user_from, messagesService.getAll(user_from.getUid(), 0), true));
- }
-
- @UserCommand(pattern = "@", help = "@ - Show recommendations and popular personal blogs")
- public CommandResult commandUsers(User user_from, URI attachment, String... arguments) {
- StringBuilder msg = new StringBuilder();
- msg.append("Recommended blogs");
- List<String> recommendedUsers = showQueriesService.getRecommendedUsers(user_from);
- if (recommendedUsers.size() > 0) {
- for (String user : recommendedUsers) {
- msg.append("\n@").append(user);
- }
- } else {
- msg.append("\nNo recommendations now. Subscribe to more blogs. ;)");
- }
- msg.append("\n\nTop 10 personal blogs:");
- List<String> topUsers = showQueriesService.getTopUsers();
- if (topUsers.size() > 0) {
- for (String user : topUsers) {
- msg.append("\n@").append(user);
- }
- } else {
- msg.append("\nNo top users. Empty DB? ;)");
- }
- return CommandResult.fromString(msg.toString());
- }
- @UserCommand(pattern = "^bl\\s+@([^\\s\\n\\+]+)", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL @username - add @username to your blacklist")
- public CommandResult blacklistUser(User user_from, URI attachment, String... arguments) {
- User blUser = userService.getUserByName(arguments[0]);
- if (!blUser.isAnonymous()) {
- PrivacyQueriesService.PrivacyResult result = privacyQueriesService.blacklistUser(user_from, blUser);
- if (result == PrivacyQueriesService.PrivacyResult.Added) {
- return CommandResult.fromString("User added to your blacklist");
- } else {
- return CommandResult.fromString("User removed from your blacklist");
- }
- }
- return CommandResult.fromString("User not found");
- }
- @UserCommand(pattern = "^bl\\s\\*(\\S+)$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "BL *tag - add *tag to your blacklist")
- public CommandResult blacklistTag(User user_from, URI attachment, String... arguments) {
- if (!user_from.isAnonymous()) {
- Tag tag = tagService.getTag(arguments[0], false);
- if (tag != null) {
- PrivacyQueriesService.PrivacyResult result = privacyQueriesService.blacklistTag(user_from, tag);
- if (result == PrivacyQueriesService.PrivacyResult.Added) {
- return CommandResult.fromString("Tag added to your blacklist");
- } else {
- return CommandResult.fromString("Tag removed from your blacklist");
- }
- }
- }
- return CommandResult.fromString("Tag not found");
- }
- @UserCommand(pattern = "\\*", help = "* - Show your tags")
- public CommandResult commandTags(User currentUser, URI attachment, String... args) {
- List<TagStats> tags = tagService.getUserTagStats(currentUser.getUid());
- String msg = "Your tags: (tag - messages)\n" +
- tags.stream()
- .map(t -> String.format("\n*%s - %d", t.getTag().getName(), t.getUsageCount())).collect(Collectors.joining());
- return CommandResult.fromString(msg);
- }
- @UserCommand(pattern = "S", help = "S - Show your subscriptions", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscriptions(User currentUser, URI attachment, String... args) {
- List<User> friends = userService.getUserFriends(currentUser.getUid());
- List<String> tags = subscriptionService.getSubscribedTags(currentUser);
- String msg = friends.size() > 0 ? "You are subscribed to users:" + friends.stream().map(u -> "\n@" + u.getName())
- .collect(Collectors.joining())
- : "You are not subscribed to any user.";
- msg += tags.size() > 0 ? "\nYou are subscribed to tags:" + tags.stream().map(t -> "\n*" + t)
- .collect(Collectors.joining())
- : "\nYou are not subscribed to any tag.";
- return CommandResult.fromString(msg);
- }
- @UserCommand(pattern = "!", help = "! - Show your favorite messages")
- public CommandResult commandFavorites(User currentUser, URI attachment, String... args) {
- List<Integer> mids = messagesService.getUserRecommendations(currentUser.getUid(), 0);
- if (mids.size() > 0) {
- return CommandResult.fromString("Favorite messages: \n" + printMessages(currentUser, mids, false));
- }
- return CommandResult.fromString("No favorite messages, try to \"like\" something ;)");
- }
- @UserCommand(pattern = "^\\!\\s+#(\\d+)", help = "! #12345 - recommend message")
- public CommandResult commandRecommend(User user, URI attachment, String... arguments) {
- int mid = NumberUtils.toInt(arguments[0], 0);
- if (mid > 0) {
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (msg.getUser() == user) {
- return CommandResult.fromString("You can't recommend your own messages.");
- }
- MessagesService.RecommendStatus status = messagesService.recommendMessage(mid, user.getUid());
- switch (status) {
- case Added:
- applicationEventPublisher.publishEvent(new LikeEvent(this, user, msg,
- subscriptionService.getUsersSubscribedToUserRecommendations(
- user.getUid(), msg)));
- return CommandResult.fromString("Message is added to your recommendations");
- case Deleted:
- return CommandResult.fromString("Message deleted from your recommendations.");
- }
- }
- return CommandResult.fromString("Message not found");
- }
- return CommandResult.fromString("Message not found");
- }
- // TODO: target notification
- @UserCommand(pattern = "^(s|u)\\s+\\@(\\S+)$", help = "S @username - subscribe to user" +
- "\nU @username - unsubscribe from user", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeUser(User user, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- User toUser = userService.getUserByName(args[1]);
- if (toUser.isAnonymous()) {
- return CommandResult.fromString("User not found");
- }
- if (subscribe) {
- if (subscriptionService.subscribeUser(user, toUser)) {
- // TODO: already subscribed case
- applicationEventPublisher.publishEvent(new SubscribeEvent(this, user, toUser));
- return CommandResult.fromString("Subscribed to @" + toUser.getName());
- }
- } else {
- if (subscriptionService.unSubscribeUser(user, toUser)) {
- return CommandResult.fromString("Unsubscribed from @" + toUser.getName());
- }
- return CommandResult.fromString("You were not subscribed to @" + toUser.getName());
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(s|u)\\s+\\*(\\S+)$", help = "S *tag - subscribe to tag" +
- "\nU *tag - unsubscribe from tag", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeTag(User user, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- Tag tag = tagService.getTag(args[1], true);
- if (subscribe) {
- if (subscriptionService.subscribeTag(user, tag)) {
- return CommandResult.fromString("Subscribed");
- }
- } else {
- if (subscriptionService.unSubscribeTag(user, tag)) {
- return CommandResult.fromString("Unsubscribed from " + tag.getName());
- }
- return CommandResult.fromString("You were not subscribed to " + tag.getName());
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(s|u)\\s+#(\\d+)$", help = "S #1234 - subscribe to comments" +
- "\nU #1234 - unsubscribe from comments", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandSubscribeMessage(User user, URI attachment, String... args) {
- boolean subscribe = args[0].equalsIgnoreCase("s");
- int mid = NumberUtils.toInt(args[1], 0);
- Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (subscribe) {
- if (subscriptionService.subscribeMessage(msg, user)) {
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, user, msg));
- return CommandResult.fromString("Subscribed");
- }
- } else {
- if (subscriptionService.unSubscribeMessage(mid, user.getUid())) {
- return CommandResult.fromString("Unsubscribed from #" + mid);
- }
- return CommandResult.fromString("You were not subscribed to #" + mid);
- }
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^(on|off)$", patternFlags = Pattern.CASE_INSENSITIVE,
- help = "ON/OFF - Enable/disable subscriptions delivery")
- public CommandResult commandOnOff(User user, URI attachment, String[] input) {
- UserService.ActiveStatus newStatus;
- String retValUpdated;
- if (input[0].toLowerCase().equals("on")) {
- newStatus = UserService.ActiveStatus.Active;
- retValUpdated = "XMPP notifications are activated";
- } else {
- newStatus = UserService.ActiveStatus.Inactive;
- retValUpdated = "XMPP notifications are disabled";
- }
- if (userService.getAllJIDs(user).stream().allMatch(jid -> userService.setActiveStatusForJID(jid, newStatus))) {
- return CommandResult.fromString(retValUpdated);
- }
- return CommandResult.fromString("Error");
- }
- @UserCommand(pattern = "^\\@([^\\s\\n\\+]+)(\\+?)$",
- help = "@username+ - Show user's info and last 20 messages")
- public CommandResult commandUser(User user, URI attachment, String... arguments) {
- User blogUser = userService.getUserByName(arguments[0]);
- int page = arguments[1].length();
- if (!blogUser.isAnonymous()) {
- List<Integer> mids = messagesService.getUserBlog(blogUser.getUid(), 0, 0);
- return CommandResult.fromString(String.format("Last messages from @%s:\n%s", arguments[0],
- printMessages(user, mids, false)));
- }
- return CommandResult.fromString("User not found");
- }
- @UserCommand(pattern = "^#(\\d+)(\\+?)$", help = "#1234 - Show message (#1234+ - message with replies)")
- public CommandResult commandShow(User user, URI attachment, String... arguments) {
- boolean showReplies = arguments[1].length() > 0;
- int mid = NumberUtils.toInt(arguments[0], 0);
- if (mid == 0) {
- return CommandResult.fromString("Error");
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (showReplies) {
- List<com.juick.Message> replies = messagesService.getReplies(user, mid);
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, user, msg));
- replies.add(0, msg);
- return CommandResult.fromString(String.join("\n",
- replies.stream().map(PlainTextFormatter::formatPostSummary).collect(Collectors.toList())));
- }
- return CommandResult.fromString(PlainTextFormatter.formatPost(msg));
- }
- return CommandResult.fromString("Message not found");
- }
- @UserCommand(pattern = "^#(\\d+)\\/(\\d+)$", help = "#1234/5 - Show reply")
- public CommandResult commandShowReply(User user, URI attachment, String... arguments) {
- int mid = NumberUtils.toInt(arguments[0], 0);
- int rid = NumberUtils.toInt(arguments[1], 0);
- com.juick.Message reply = messagesService.getReply(mid, rid);
- if (reply != null) {
- return CommandResult.fromString(PlainTextFormatter.formatPost(reply));
- }
- return CommandResult.fromString("Reply not found");
- }
- @UserCommand(pattern = "^\\*(\\S+)(\\+?)$", help = "*tag - Show last messages with tag")
- public CommandResult commandShowTag(User user, URI attachment, String... arguments) {
- if (StringUtils.isNotEmpty(attachment.toString())) {
- // new message with tag
- return CommandResult.fromString(StringUtils.EMPTY);
- }
- Tag tag = tagService.getTag(arguments[0], false);
- if (tag != null) {
- // TODO: synonyms
- List<Integer> mids = messagesService.getTag(tag.TID, user.getUid(), 0, 10);
- return CommandResult.fromString("Last messages with *" + tag.getName() + ":\n" + printMessages(user, mids, true));
- }
- return CommandResult.fromString("Tag not found");
- }
- @UserCommand(pattern = "^D #(\\d+)$", help = "D #1234 - Delete post", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeletePost(User user, URI attachment, String... args) {
- int mid = Integer.valueOf(args[0]);
- Message message = messagesService.getMessage(mid);
- if (message != null && messagesService.deleteMessage(user.getUid(), mid)) {
- applicationEventPublisher.publishEvent(new DeleteMessageEvent(this, message));
- return CommandResult.fromString("Message deleted");
- }
- return CommandResult.fromString("This is not your message");
- }
- @UserCommand(pattern = "^D #(\\d+)(\\.|\\-|\\/)(\\d+)$", help = "D #1234/5 - Delete comment", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeleteReply(User user, URI attachment, String... args) {
- int mid = Integer.valueOf(args[0]);
- int rid = Integer.valueOf(args[2]);
- if (messagesService.deleteReply(user.getUid(), mid, rid)) {
- return CommandResult.fromString("Reply deleted");
- } else {
- return CommandResult.fromString("This is not your reply");
- }
- }
- @UserCommand(pattern = "^(D L|DL|D LAST)$", help = "D L - Delete last message", patternFlags = Pattern.CASE_INSENSITIVE)
- public CommandResult commandDeleteLast(User user, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^\\?\\s+\\@([a-zA-Z0-9\\-\\.\\@]+)\\s+([\\s\\S]+)$", help = "? @user string - search in user messages")
- public CommandResult commandSearch(User user, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^\\?\\s+([\\s\\S]+)$", help = "? string - search in all messages")
- public CommandResult commandSearchAll(User user, URI attachment, String... args) {
- return CommandResult.fromString("Temporarily unavailable");
- }
- @UserCommand(pattern = "^(#+)$", help = "# - Show last messages from your feed (## - second page, ...)")
- public CommandResult commandMyFeed(User user, URI attachment, String... arguments) {
- // number of # is the page count
- int page = arguments[0].length() - 1;
- List<Integer> mids = messagesService.getMyFeed(user.getUid(), page, false);
- if (mids.size() > 0) {
- return CommandResult.fromString("Your feed: \n" + printMessages(user, mids, true));
- }
- return CommandResult.fromString("Your feed is empty");
- }
- @UserCommand(pattern = "^(#|\\.)(\\d+)((\\.|\\-|\\/)(\\d+))?\\s([\\s\\S]+)?",
- help = "#1234 *tag *tag2 - edit tags\n#1234 text - reply to message")
- public CommandResult EditOrReply(User user, @Nonnull URI attachment, String... args) throws Exception {
- int mid = NumberUtils.toInt(args[1]);
- int rid = NumberUtils.toInt(args[4], 0);
- String txt = StringUtils.defaultString(args[5]);
- Message msg = messagesService.getMessage(mid);
- Pair<String, List<Tag>> messageTags = tagService.fromString(txt);
- if (messageTags.getRight().size() > 0) {
- if (user.getUid() != msg.getUser().getUid()) {
- return CommandResult.fromString("It is not your message");
- }
- if (!CollectionUtils.isEqualCollection(tagService.updateTags(mid, messageTags.getRight()), msg.getTags())) {
- return CommandResult.fromString("Tags are updated");
- } else {
- return CommandResult.fromString("Tags are NOT updated (5 tags maximum?)");
- }
- } else {
- boolean haveAttachment = StringUtils.isNotEmpty(attachment.toString());
- String attachmentFName = null;
- String attachmentType = null;
- if (haveAttachment) {
- attachmentFName = attachment.getScheme().equals("juick") ? attachment.getHost()
- : HttpUtils.downloadImage(attachment.toURL(), tmpDir).getHost();
- attachmentType = attachmentFName.substring(attachmentFName.length() - 3);
- }
- int newrid = messagesService.createReply(mid, rid, user, txt, attachmentType);
- if (haveAttachment) {
- String fname = String.format("%d-%d.%s", mid, newrid, attachmentType);
- imagesService.saveImageWithPreviews(attachmentFName, fname);
- }
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, user, msg));
- Message original = messagesService.getMessage(mid);
- subscriptionService.subscribeMessage(original, user);
- Message reply = messagesService.getReply(mid, newrid);
- applicationEventPublisher.publishEvent(new MessageEvent(this, reply, subscriptionService.getUsersSubscribedToComments(original, reply)));
- return CommandResult.build(reply,"Reply posted.\n#" + mid + "/" + newrid + " "
- + "https://juick.com/m/" + mid + "#" + newrid,
- String.format("[Reply](%s) posted", PlainTextFormatter.formatUrl(reply)));
- }
- }
-
- String printMessages(User visitor, List<Integer> mids, boolean crop) {
- return messagesService.getMessages(visitor, mids).stream()
- .sorted(Collections.reverseOrder())
- .map(PlainTextFormatter::formatPostSummary).collect(Collectors.joining("\n\n"));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/EmailManager.java b/juick-server/src/main/java/com/juick/server/EmailManager.java
deleted file mode 100644
index 1cdafac6..00000000
--- a/juick-server/src/main/java/com/juick/server/EmailManager.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.service.EmailService;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import com.juick.service.component.*;
-import com.juick.util.MessageUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import static com.juick.formatters.PlainTextFormatter.formatPost;
-import static com.juick.formatters.PlainTextFormatter.formatUrl;
-
-@Component
-public class EmailManager implements NotificationListener {
-
- public static final String MSGID_PATTERN = "\\.|@|<";
-
- private static final Logger logger = LoggerFactory.getLogger(EmailManager.class);
- @Inject
- private EmailService emailService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Override
- public void processMessageEvent(@Nonnull MessageEvent event) {
- Message msg = event.getMessage();
- List<User> subscribedUsers = event.getUsers();
- if (msg.isService()) {
- return;
- }
- if (MessageUtils.isPM(msg)) {
- String subject = String.format("Private message from %s", msg.getUser().getName());
- emailService.getEmails(msg.getTo().getUid(), true).forEach(email -> {
- emailNotify(email, subject, msg);
- });
- } else if (MessageUtils.isReply(msg)) {
- Message originalMessage = messagesService.getMessage(msg.getMid());
- String subject = String.format("New reply to %s", originalMessage.getUser().getName());
- subscribedUsers.stream()
- .flatMap(user -> emailService.getEmails(user.getUid(), true).stream())
- .forEach(email -> emailNotify(email, subject, msg));
- } else {
- String subject = String.format("New message from %s", msg.getUser().getName());
- subscribedUsers
- .forEach(user -> emailService.getEmails(user.getUid(), true)
- .forEach(email -> emailNotify(email, subject, msg)));
- }
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
-
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
-
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
-
- }
-
- private void emailNotify(String email, String subject, Message msg) {
- Map<String, String> headers = new HashMap<>();
- if (!MessageUtils.isPM(msg)) {
- headers.put("Message-ID", String.format("<%d.%d@juick.com>", msg.getMid(), msg.getRid()));
- }
- if (MessageUtils.isReply(msg)) {
- if (msg.getReplyto() > 0) {
- Message replyto = messagesService.getReply(msg.getMid(), msg.getReplyto());
- headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", replyto.getMid(), replyto.getRid()));
- } else {
- Message original = messagesService.getMessage(msg.getMid());
- headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", original.getMid(), original.getRid()));
- }
- }
- String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user," +
- " discussion, tag or mentioned. Reply to this email directly or view it on Juick: %s.",
- formatPost(msg), formatUrl(msg));
- String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid());
- String htmlText = String.format("%s<br /><br />--<br />You are receiving this because you are subscribed to this user" +
- ", discussion, tag or mentioned. Reply to this email directly or <a href=\"%s\"><img src=\"https://api.juick.com/thread/mark_read/%d-%d.gif?hash=%s\" />view it</a> on Juick." +
- "<br /><a href=\"https://juick.com/settings?hash=%s\">Configure or disable notifications</a>",
- msg.isHtml() ? msg.getText() : MessageUtils.formatHtml(msg), formatUrl(msg),
- msg.getMid(), msg.getRid(), hash, hash);
- sendEmail(email, subject, plainText, htmlText, headers);
- }
- public void sendEmail(String to, String subject, String textPart, String htmlPart, Map<String, String> messageHeaders) {
- Properties prop = System.getProperties();
- prop.put("mail.smtp.starttls.enable", "true");
- Session session = Session.getDefaultInstance(prop);
- try {
- Transport transport = session.getTransport("smtp");
- MimeMessage message = new MimeMessage(session) {
- protected void updateMessageID() throws MessagingException {
- for (Map.Entry<String, String> entry: messageHeaders.entrySet()) {
- setHeader(entry.getKey(), entry.getValue());
- }
- }
- };
- message.setFrom(new InternetAddress("juick@juick.com"));
- message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
- message.setSubject(subject);
- MimeBodyPart textBodyPart = new MimeBodyPart();
- textBodyPart.setContent(textPart, "text/plain; charset=UTF-8");
-
- Multipart multipart = new MimeMultipart("alternative");
- multipart.addBodyPart(textBodyPart);
- if (StringUtils.isNotBlank(htmlPart)) {
- MimeBodyPart htmlBodyPart = new MimeBodyPart();
- htmlBodyPart.setContent(htmlPart, "text/html; charset=UTF-8");
- multipart.addBodyPart(htmlBodyPart);
- }
- message.setContent(multipart);
- User emailUser = userService.getUserByEmail(to);
- if (!emailUser.isAnonymous()) {
- message.setHeader("List-Id", "Juick notifications <mail-notifications.juick.com>");
- message.setHeader("List-Post", "<mailto:juick@juick.com>");
- message.setHeader("List-Owner", "<mailto:support@juick.com>");
- message.setHeader("List-Archive", "<https://juick.com/>");
- message.setHeader("List-Unsubscribe", String.format("https://juick.com/settings/unsubscribe?hash=%s",
- userService.getHashByUID(emailUser.getUid())));
- message.setHeader("List-Unsubscribe-Post", "List-Unsubscribe=One-Click");
- }
- message.saveChanges();
- transport.connect();
- transport.sendMessage(message, message.getAllRecipients());
- } catch (MessagingException ex) {
- logger.error("mail exception", ex);
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/KeystoreManager.java b/juick-server/src/main/java/com/juick/server/KeystoreManager.java
deleted file mode 100644
index 97c3a224..00000000
--- a/juick-server/src/main/java/com/juick/server/KeystoreManager.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.juick.server;
-
-import com.juick.server.api.activity.model.objects.Person;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.util.Base64Utils;
-
-import javax.annotation.PostConstruct;
-import javax.net.ssl.KeyManagerFactory;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.*;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-@Component
-public class KeystoreManager {
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server");
- @Value("${keystore:../juick.p12}")
- private String keystore;
- @Value("${keystore_password:secret}")
- private String keystorePassword;
-
- private KeyStore ks;
-
- private KeyManagerFactory kmf;
-
- @PostConstruct
- public void init() {
- try (InputStream ksIs = new FileInputStream(keystore)) {
- ks = KeyStore.getInstance("PKCS12");
- ks.load(ksIs, keystorePassword.toCharArray());
- kmf = KeyManagerFactory.getInstance(KeyManagerFactory
- .getDefaultAlgorithm());
- kmf.init(ks, keystorePassword.toCharArray());
- } catch (IOException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException e) {
- logger.error("Keystore error", e);
- }
- }
-
- public KeyStore getKeystore() {
- return ks;
- }
-
- public KeyManagerFactory getKeymanagerFactory() {
- return kmf;
- }
-
- private KeyPair getKeyPair() {
- Key privateKey = null;
- try {
- privateKey = ks.getKey("1", keystorePassword.toCharArray());
- Certificate certificate = ks.getCertificate("1");
- return new KeyPair(certificate.getPublicKey(), (PrivateKey) privateKey);
- } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
- e.printStackTrace();
- }
- return null;
- }
- public PrivateKey getPrivateKey() {
- return getKeyPair().getPrivate();
- }
- public PublicKey getPublicKey() {
- return getKeyPair().getPublic();
- }
- public String getPublicKeyPem() {
- String[] key = Base64Utils.encodeToString(getKeyPair().getPublic().getEncoded()).split("(?<=\\G.{64})");
- return String.format("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
- Arrays.asList(key).stream().collect(Collectors.joining("\n")));
- }
- public static PublicKey publicKeyOf(Person person) {
- String pubkeyPem = person.getPublicKey().getPublicKeyPem();
- String[] rawKey = pubkeyPem.split("\\n");
- String pubkeyData = String.join("", Arrays.asList(rawKey).subList(1, rawKey.length - 1));
- try{
- byte[] byteKey = Base64Utils.decodeFromString(pubkeyData);
- X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
- KeyFactory kf = KeyFactory.getInstance("RSA");
- return kf.generatePublic(X509publicKey);
- }
- catch(Exception e){
- e.printStackTrace();
- }
- return null;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/ServerManager.java b/juick-server/src/main/java/com/juick/server/ServerManager.java
deleted file mode 100644
index ef848526..00000000
--- a/juick-server/src/main/java/com/juick/server/ServerManager.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.juick.Message;
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.service.MessagesService;
-import com.juick.service.SubscriptionService;
-import com.juick.service.UserService;
-import com.juick.service.component.LikeEvent;
-import com.juick.service.component.MessageEvent;
-import com.juick.service.component.MessageReadEvent;
-import com.juick.service.component.NotificationListener;
-import com.juick.service.component.PingEvent;
-import com.juick.service.component.SubscribeEvent;
-import com.juick.service.component.TopEvent;
-import com.juick.util.MessageUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-import org.springframework.web.socket.TextMessage;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.stream.Collectors;
-
-/**
- * @author Ugnich Anton
- */
-@Component
-public class ServerManager implements NotificationListener {
- private static Logger logger = LoggerFactory.getLogger(ServerManager.class);
-
- @Inject
- private ObjectMapper jsonMapper;
- @Inject
- private MessagesService messagesService;
- @Inject
- private WebsocketManager wsHandler;
- @Inject
- private SubscriptionService subscriptionService;
- @Inject
- private UserService userService;
- private CopyOnWriteArrayList<EventSession> sessions = new CopyOnWriteArrayList<>();
-
- @Value("${service_user:juick}")
- private String serviceUsername;
-
- private User serviceUser;
-
- @PostConstruct
- public void init() {
- serviceUser = userService.getUserByName(serviceUsername);
- }
-
-
- private void onJuickPM(final User to, final com.juick.Message jmsg) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.getUid() == to.getUid()) || c.visitor.equals(serviceUser))
- .forEach(c -> {
- try {
- logger.debug("sending pm to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
- messageEvent(jmsg, Collections.singletonList(to));
- }
-
- private void onJuickMessagePost(final com.juick.Message jmsg, List<User> subscribedUsers) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- List<Integer> uids = subscribedUsers
- .stream().map(User::getUid).collect(Collectors.toList());
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.isAnonymous()) // anonymous users
- || c.visitor.equals(serviceUser) // services
- || (!c.legacy && uids.contains(c.visitor.getUid()))) // subscriptions
- .forEach(c -> {
- try {
- logger.debug("sending message to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- wsHandler.getClients().stream().filter(c ->
- c.legacy && c.allMessages) // legacy all posts
- .forEach(c -> {
- try {
- logger.debug("sending message to legacy client {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
- messageEvent(jmsg, subscribedUsers);
- messageEvent(jmsg, Collections.singletonList(AnonymousUser.INSTANCE));
- }
-
- private void onJuickMessageReply(final com.juick.Message jmsg, final List<User> subscribedUsers) {
- try {
-
- String json = jsonMapper.writeValueAsString(jmsg);
- com.juick.Message op = messagesService.getMessage(jmsg.getMid());
- List<Integer> threadUsers =
- subscribedUsers
- .stream().map(User::getUid).collect(Collectors.toList());
- synchronized (wsHandler.getClients()) {
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor.isAnonymous()) // anonymous users
- || c.visitor.equals(serviceUser) // services
- || (!c.legacy && threadUsers.contains(c.visitor.getUid()))) // subscriptions
- .forEach(c -> {
- try {
- logger.debug("sending reply to {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- wsHandler.getClients().stream().filter(c ->
- (c.legacy && c.allReplies) || (c.legacy && c.MID == jmsg.getMid())) // legacy replies
- .forEach(c -> {
- try {
- logger.debug("sending reply to legacy client {}", c.visitor.getUid());
- c.sendMessage(new TextMessage(json));
- } catch (IOException e) {
- logger.warn("ws error", e);
- }
- });
- }
- } catch (JsonProcessingException e) {
- logger.warn("Invalid JSON", e);
- }
- messageEvent(jmsg, subscribedUsers);
- messageEvent(jmsg, Collections.singletonList(AnonymousUser.INSTANCE));
- }
-
- @Override
- public void processMessageEvent(MessageEvent event) {
- com.juick.Message jmsg = event.getMessage();
- List<User> subscribedUsers = event.getUsers();
- if (jmsg.isService()) {
- readEvent(jmsg, Collections.singletonList(serviceUser));
- return;
- }
- if (MessageUtils.isPM(jmsg)) {
- onJuickPM(jmsg.getTo(), jmsg);
- } else if (!MessageUtils.isReply(jmsg)) {
- // to get full message with attachment, etc.
- onJuickMessagePost(messagesService.getMessage(jmsg.getMid()), subscribedUsers);
- } else {
- // to get quote and attachment
- Message op = messagesService.getMessage(jmsg.getMid());
- com.juick.Message reply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- subscriptionService.getUsersSubscribedToComments(op, reply, true).stream()
- .filter(u -> userService.isReplyToBL(u, reply))
- .forEach(b -> messagesService.setLastReadComment(b, reply.getMid(), reply.getRid()));
- onJuickMessageReply(reply, subscribedUsers);
- }
- messageEvent(jmsg, Collections.singletonList(serviceUser));
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
-
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
- User user = messageReadEvent.getUser();
- Message source = messageReadEvent.getMessage();
-
- logger.info("Message read event from {} for {}", user.getUid(), source.getMid());
- Message serviceMessage = new Message();
- serviceMessage.setService(true);
- serviceMessage.setUser(user);
- serviceMessage.setMid(source.getMid());
- serviceMessage.setUnread(false);
- wsHandler.getClients().stream().filter(c ->
- (!c.legacy && c.visitor == user) || c.visitor.equals(serviceUser)
- ).forEach(u -> {
- try {
- u.sendMessage(new TextMessage(jsonMapper.writeValueAsString(serviceMessage)));
- } catch (IOException e) {
- logger.error("JSON error", e);
- }
- });
- readEvent(serviceMessage, Collections.singletonList(serviceUser));
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
- User topUser = topEvent.getMessage().getUser();
- topEvent(topEvent.getMessage(), Arrays.asList(topUser, serviceUser));
- }
-
- public void topEvent(Message msg, List<User> subscribers){
- sendSseEvent(msg, "top", subscribers);
- }
-
- public void readEvent(Message msg, List<User> subscribers){
- sendSseEvent(msg, "read", subscribers);
- }
-
- public void messageEvent(Message msg, List<User> subscribers){
- sendSseEvent(msg, "msg", subscribers);
- }
-
- private void sendSseEvent(Message msg, String name, List<User> subscribers) {
- List<EventSession> deadEmitters = new ArrayList<>();
- this.sessions.stream().filter(s -> subscribers.contains(s.user)).forEach(session -> {
- try {
- SseEmitter.SseEventBuilder builder = SseEmitter.event()
- .name(name)
- .data(msg);
- session.getEmitter().send(builder);
- } catch (Exception e) {
- deadEmitters.add(session);
- }
- });
- this.sessions.removeAll(deadEmitters);
- }
-
- public static class EventSession {
- private User user;
- private SseEmitter emitter;
-
- public EventSession(User user, SseEmitter sseEmitter) {
- this.user = user;
- this.emitter = sseEmitter;
- }
-
- public User getUser() {
- return user;
- }
-
- public SseEmitter getEmitter() {
- return emitter;
- }
- }
-
- public CopyOnWriteArrayList<EventSession> getSessions() {
- return sessions;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/SignatureManager.java b/juick-server/src/main/java/com/juick/server/SignatureManager.java
deleted file mode 100644
index b3b7a301..00000000
--- a/juick-server/src/main/java/com/juick/server/SignatureManager.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.juick.server;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.juick.server.api.activity.model.Context;
-import com.juick.server.api.activity.model.objects.Person;
-import com.juick.server.api.webfinger.model.Account;
-import com.juick.server.api.webfinger.model.Link;
-import com.juick.util.DateFormattersHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-import org.tomitribe.auth.signatures.Signature;
-import org.tomitribe.auth.signatures.Signer;
-import org.tomitribe.auth.signatures.Verifier;
-import rocks.xmpp.addr.Jid;
-
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.SignatureException;
-import java.time.Instant;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-
-import static com.juick.server.api.activity.model.Context.ACTIVITY_MEDIA_TYPE;
-
-@Component
-public class SignatureManager {
- private static final Logger logger = LoggerFactory.getLogger(ActivityPubManager.class);
- @Inject
- private KeystoreManager keystoreManager;
- @Inject
- private ObjectMapper jsonMapper;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Inject
- private RestTemplate apClient;
-
- public void post(Person from, Person to, Context data) throws IOException {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(to.getInbox());
- URI inbox = uriComponentsBuilder.build().toUri();
- Instant now = Instant.now();
- String requestDate = DateFormattersHolder.getHttpDateFormatter().format(now);
- Signature templateSignature = new Signature(from.getPublicKey().getId(), "rsa-sha256", null,
- "(request-target)", "host", "date");
- Signer signer = new Signer(keystoreManager.getPrivateKey(), templateSignature);
- Map<String, String> headers = new HashMap<>();
- headers.put("host", inbox.getHost());
- headers.put("date", requestDate);
- Signature signature = signer.sign("POST", inbox.getPath(), headers);
- HttpHeaders requestHeaders = new HttpHeaders();
- requestHeaders.add("Content-Type", Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE);
- requestHeaders.add("Date", requestDate);
- requestHeaders.add("Signature", signature.toString().substring(10));
- HttpEntity<Context> request = new HttpEntity<>(Context.build(data), requestHeaders);
- //boolean valid = verifySignature(Signature.fromString(requestHeaders.getFirst("Signature")),
- // keystoreManager.getPublicKey(), "POST", inbox.getPath(), headers);
- logger.info("Sending context: {}", jsonMapper.writeValueAsString(data));
- logger.info("Request date: {}", requestDate);
- ResponseEntity<Void> response = apClient.postForEntity(inbox, request, Void.class);
- logger.info("accepted follower: {}", response.getStatusCodeValue());
-
- }
- public boolean verifySignature(String signatureString, URI actor, String method, String path, Map<String, String> headers) {
- Optional<Context> context = getContext(actor);
- if (context.isPresent() && context.get() instanceof Person) {
- Person person = (Person) context.get();
- Key key = KeystoreManager.publicKeyOf(person);
- Verifier verifier = new Verifier(key, Signature.fromString(signatureString));
- try {
- boolean result = verifier.verify(method, path, headers);
- logger.info("signature is valid: {}", result);
- return result;
- } catch (NoSuchAlgorithmException | SignatureException | IOException e) {
- logger.info("signature exception", e);
- return false;
- }
- }
- logger.info("person not found");
- return false;
- }
- public Optional<Context> getContext(URI contextUri) {
- Context context = apClient.getForEntity(contextUri, Context.class).getBody();
- if (context == null) {
- logger.warn("Cannot identify {}", contextUri);
- return Optional.empty();
- }
- return Optional.of(context);
- }
- public Optional<Context> discoverPerson(String acct) {
- Jid acctId = Jid.of(acct);
- URI resourceUri = UriComponentsBuilder.fromUriString(
- String.format("https://%s/.well-known/webfinger?resource=acct:%s", acctId.getDomain(), acct)).build().toUri();
- Account acctData = apClient.getForEntity(resourceUri, Account.class).getBody();
- if (acctData != null) {
- for (Link l : acctData.getLinks()) {
- if (l.getRel().equals("self") && l.getType().equals(ACTIVITY_MEDIA_TYPE)) {
- return getContext(URI.create(l.getHref()));
- }
- }
- }
- return Optional.empty();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/TelegramBotManager.java b/juick-server/src/main/java/com/juick/server/TelegramBotManager.java
deleted file mode 100644
index 8e8d0104..00000000
--- a/juick-server/src/main/java/com/juick/server/TelegramBotManager.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.User;
-import com.juick.service.component.*;
-import com.juick.model.AnonymousUser;
-import com.juick.model.CommandResult;
-import com.juick.server.util.HttpUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.TelegramService;
-import com.juick.service.UserService;
-import com.juick.util.MessageUtils;
-import com.pengrad.telegrambot.Callback;
-import com.pengrad.telegrambot.TelegramBot;
-import com.pengrad.telegrambot.UpdatesListener;
-import com.pengrad.telegrambot.model.Message;
-import com.pengrad.telegrambot.model.MessageEntity;
-import com.pengrad.telegrambot.model.PhotoSize;
-import com.pengrad.telegrambot.model.Update;
-import com.pengrad.telegrambot.model.request.ParseMode;
-import com.pengrad.telegrambot.request.GetFile;
-import com.pengrad.telegrambot.request.SendMessage;
-import com.pengrad.telegrambot.request.SendPhoto;
-import com.pengrad.telegrambot.request.SetWebhook;
-import com.pengrad.telegrambot.response.GetFileResponse;
-import com.pengrad.telegrambot.response.SendResponse;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.util.*;
-
-import static com.juick.formatters.PlainTextFormatter.formatPost;
-import static com.juick.formatters.PlainTextFormatter.formatUrl;
-
-/**
- * Created by vt on 12/05/16.
- */
-public class TelegramBotManager implements NotificationListener {
- private static final Logger logger = LoggerFactory.getLogger(TelegramBotManager.class);
-
- private TelegramBot bot;
-
- @Value("${telegram_token:12345678}")
- private String telegramToken;
- @Value("${telegram_debug:false}")
- private boolean telegramDebug;
- @Inject
- private TelegramService telegramService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private CommandsManager commandsManager;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
-
- private static final String MSG_LINK = "🔗";
-
- @PostConstruct
- public void init() {
- if (StringUtils.isBlank(telegramToken)) {
- logger.info("telegram token is not set, exiting");
- return;
- }
- bot = new TelegramBot(telegramToken);
- if (!telegramDebug) {
- try {
- SetWebhook webhook = new SetWebhook().url("https://api.juick.com/tlgmbtwbhk");
- if (!bot.execute(webhook).isOk()) {
- logger.error("error setting webhook");
- }
- } catch (Exception e) {
- logger.warn("couldn't initialize telegram bot", e);
- }
- } else {
- bot.setUpdatesListener(updates -> {
- updates.forEach(this::processUpdate);
- return UpdatesListener.CONFIRMED_UPDATES_ALL;
- });
- }
- }
-
- public void processUpdate(Update update) {
- Message message = update.message();
- if (update.message() == null) {
- message = update.editedMessage();
- if (message == null) {
- logger.error("error parsing telegram update: {}", update);
- return;
- }
- }
- User user_from = userService.getUserByUID(telegramService.getUser(message.chat().id())).orElse(AnonymousUser.INSTANCE);
- logger.info("Found juick user {}", user_from.getUid());
-
- String username = message.from().username();
- if (username == null) {
- username = message.from().firstName();
- }
- if (!user_from.isAnonymous()) {
- URI attachment = URI.create(StringUtils.EMPTY);
- if (message.photo() != null) {
- String fileId = Arrays.stream(message.photo()).max(Comparator.comparingInt(PhotoSize::fileSize))
- .orElse(new PhotoSize()).fileId();
- if (StringUtils.isNotEmpty(fileId)) {
- GetFile request = new GetFile(fileId);
- GetFileResponse response = bot.execute(request);
- logger.info("got file {}", response.file());
- try {
- URL fileURL = new URL(bot.getFullFilePath(response.file()));
- attachment = HttpUtils.downloadImage(fileURL, tmpDir);
- } catch (Exception e) {
- logger.warn("attachment exception", e);
- }
- logger.info("received {}", attachment);
- }
- }
- String text = message.text();
- if (StringUtils.isBlank(text)) {
- text = message.caption();
- }
- if (StringUtils.isBlank(text)) {
- text = StringUtils.EMPTY;
- }
- if (StringUtils.isNotEmpty(text) || StringUtils.isNotEmpty(attachment.toString())) {
- if (text.equalsIgnoreCase("LOGIN")
- || text.equalsIgnoreCase("PING")
- || text.equalsIgnoreCase("HELP")
- || text.equalsIgnoreCase("/login")
- || text.equalsIgnoreCase("/logout")
- || text.equalsIgnoreCase("/start")
- || text.equalsIgnoreCase("/help")) {
- String msgUrl = "http://juick.com/login?hash=" + userService.getHashByUID(user_from.getUid());
- String msg = String.format("Hi, %s!\nYou can post messages and images to Juick there.\n" +
- "Tap to [log into website](%s) to get more info", user_from.getName(), msgUrl);
- telegramNotify(message.from().id().longValue(), msg, new com.juick.Message());
- } else {
- Message replyMessage = message.replyToMessage();
- if (replyMessage != null) {
- MessageEntity[] entities = replyMessage.entities();
- if (entities == null) {
- entities = replyMessage.captionEntities();
- }
- if (entities != null) {
- Optional<MessageEntity> juickLink = Arrays.stream(entities)
- .filter(this::isJuickLink)
- .findFirst();
- if (juickLink.isPresent()) {
- if (StringUtils.isNotEmpty(juickLink.get().url())) {
- UriComponents uriComponents = UriComponentsBuilder.fromUriString(
- juickLink.get().url()).build();
- String path = uriComponents.getPath();
- if (StringUtils.isNotEmpty(path) && path.length() > 1) {
- int mid = 0;
- try {
- mid = Integer.valueOf(path.substring(3));
- } catch (NumberFormatException e) {
- logger.warn("wrong mid received");
- return;
- }
- String prefix = String.format("#%d ", mid);
- if (StringUtils.isNotEmpty(uriComponents.getFragment())) {
- int rid = Integer.valueOf(uriComponents.getFragment());
- prefix = String.format("#%d/%d ", mid, rid);
- }
- CommandResult result = null;
- try {
- result = commandsManager.processCommand(user_from, prefix + text, attachment);
- String messageTxt = StringUtils.isNotEmpty(result.getMarkdown()) ? result.getMarkdown()
- : "Unknown error or unsupported command";
- telegramNotify(message.from().id().longValue(), messageTxt, new com.juick.Message());
- } catch (Exception e) {
- logger.warn("telegram exception", e);
- }
- } else {
- logger.warn("invalid path: {}", path);
- }
- } else {
- logger.warn("invalid entity: {}", juickLink);
- }
- } else {
- telegramNotify(message.from().id().longValue(),
- "Can not reply to this message", replyMessage.messageId(), new com.juick.Message());
- }
- } else {
- telegramNotify(message.from().id().longValue(),
- "Can not reply to this message", replyMessage.messageId(), new com.juick.Message());
- }
- } else {
- try {
- CommandResult result = commandsManager.processCommand(user_from, text, attachment);
- String messageTxt = StringUtils.isNotEmpty(result.getMarkdown()) ? result.getMarkdown()
- : "Unknown error or unsupported command";
- telegramNotify(message.from().id().longValue(), messageTxt, new com.juick.Message());
- } catch (Exception e) {
- logger.warn("telegram reply exception", e);
- }
- }
- }
- }
- } else {
- List<Long> chats = telegramService.getAnonymous();
- if (!chats.contains(message.chat().id())) {
- logger.info("added chat with {}", username);
- telegramService.createTelegramUser(message.from().id(), username);
- }
- telegramSignupNotify(message.from().id().longValue(), userService.getSignUpHashByTelegramID(message.from().id().longValue(), username));
- }
- }
-
- private boolean isJuickLink(MessageEntity e) {
- return e.offset() == 0 && e.type().equals(MessageEntity.Type.text_link) && e.length() == 2;
- }
-
- public void telegramNotify(Long chatId, String msg, @Nonnull com.juick.Message source) {
- telegramNotify(chatId, msg, 0, source);
- }
-
- public void telegramNotify(Long chatId, String msg, Integer replyTo, @Nonnull com.juick.Message source) {
- String attachment = MessageUtils.attachmentUrl(source);
- if (StringUtils.isEmpty(attachment)) {
- SendMessage telegramMessage = new SendMessage(chatId, msg);
- if (replyTo > 0) {
- telegramMessage.replyToMessageId(replyTo);
- }
- telegramMessage.parseMode(ParseMode.Markdown).disableWebPagePreview(true);
- bot.execute(telegramMessage, new Callback<SendMessage, SendResponse>() {
- @Override
- public void onResponse(SendMessage request, SendResponse response) {
- processTelegramResponse(chatId, response, source);
- }
-
- @Override
- public void onFailure(SendMessage request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- } else {
- SendPhoto telegramPhoto = new SendPhoto(chatId, attachment);
- String trimmedPost = msg.length() > 1024 ? msg.substring(0, 1023) + "..." : msg;
- telegramPhoto.caption(trimmedPost);
- if (replyTo > 0) {
- telegramPhoto.replyToMessageId(replyTo);
- }
- telegramPhoto.parseMode(ParseMode.Markdown);
- bot.execute(telegramPhoto, new Callback<SendPhoto, SendResponse>() {
- @Override
- public void onResponse(SendPhoto request, SendResponse response) {
- processTelegramResponse(chatId, response, source);
- }
-
- @Override
- public void onFailure(SendPhoto request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- }
- }
-
- private void processTelegramResponse(Long chatId, SendResponse response, com.juick.Message source) {
- int userId = telegramService.getUser(chatId);
- if (!response.isOk()) {
- if (response.errorCode() == 403) {
- // remove from anonymous users
- telegramService.getAnonymous().stream().filter(c -> c.equals(chatId)).findFirst().ifPresent(
- d -> {
- telegramService.deleteAnonymous(d);
- logger.info("deleted {} chat", d);
- }
- );
- if (userId > 0) {
- User userToDelete = userService.getUserByUID(userId)
- .orElseThrow(IllegalStateException::new);
- boolean status = telegramService.deleteTelegramUser(userToDelete.getUid());
- logger.info("deleting telegram id of @{} : {}", userToDelete.getName(), status);
- }
- } else {
- logger.warn("error response, isOk: {}, errorCode: {}, description: {}",
- response.isOk(), response.errorCode(), response.description());
- }
- } else {
- if (MessageUtils.isReply(source)) {
- messagesService.setLastReadComment(userService.getUserByUID(userId)
- .orElseThrow(IllegalStateException::new), source.getMid(), source.getRid());
- User user = userService.getUserByUID(userId).orElseThrow(IllegalStateException::new);
- userService.updateLastSeen(user);
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, user, source));
- }
- }
- }
-
- public void telegramSignupNotify(Long telegramId, String hash) {
- bot.execute(new SendMessage(telegramId,
- String.format("You are subscribed to all Juick messages. " +
- "[Create or link](http://juick.com/signup?type=durov&hash=%s) " +
- "an existing Juick account to get your subscriptions and ability to post messages", hash))
- .parseMode(ParseMode.Markdown), new Callback<SendMessage, SendResponse>() {
- @Override
- public void onResponse(SendMessage request, SendResponse response) {
- logger.info("got response: {}", response.message());
- }
-
- @Override
- public void onFailure(SendMessage request, IOException e) {
- logger.warn("telegram failure", e);
- }
- });
- }
-
- @Override
- public void processMessageEvent(MessageEvent messageEvent) {
- com.juick.Message jmsg = messageEvent.getMessage();
- List<User> subscribedUsers = messageEvent.getUsers();
- if (jmsg.isService()) {
- return;
- }
- String msgUrl = formatUrl(jmsg);
- if (MessageUtils.isPM(jmsg)) {
- telegramService.getTelegramIdentifiers(Collections.singletonList(jmsg.getTo()))
- .forEach(c -> telegramNotify(c, formatPost(jmsg, true), jmsg));
- } else if (MessageUtils.isReply(jmsg)) {
- com.juick.Message op = messagesService.getMessage(jmsg.getMid());
- String fmsg = String.format("[%s](%s) %s", MSG_LINK, msgUrl, formatPost(jmsg, true));
- telegramService.getTelegramIdentifiers(
- subscribedUsers
- ).forEach(c -> telegramNotify(c, fmsg, jmsg));
- } else {
- String msg = String.format("[%s](%s) %s", MSG_LINK, msgUrl, formatPost(jmsg, true));
-
- List<Long> users = telegramService.getTelegramIdentifiers(subscribedUsers);
- List<Long> chats = telegramService.getAnonymous();
- // registered subscribed users
-
- users.forEach(c -> telegramNotify(c, msg, jmsg));
- // anonymous
- chats.stream().filter(u -> telegramService.getUser(u) == 0).forEach(c -> telegramNotify(c, msg, jmsg));
- }
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
- User liker = likeEvent.getUser();
- com.juick.Message message = likeEvent.getMessage();
- List<User> subscribers = likeEvent.getSubscribers();
- logger.info("Like received in tg listener");
- if (!userService.isInBLAny(message.getUser().getUid(), liker.getUid())) {
- telegramService.getTelegramIdentifiers(Collections.singletonList(message.getUser()))
- .forEach(c -> telegramNotify(c, String.format("%s recommends your [post](%s)",
- MessageUtils.getMarkdownUser(liker), formatUrl(message)), new com.juick.Message()));
- }
- telegramService.getTelegramIdentifiers(subscribers)
- .forEach(c -> telegramNotify(c, String.format("%s recommends you someone's [post](%s)",
- MessageUtils.getMarkdownUser(liker), formatUrl(message)), new com.juick.Message()));
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
-
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
- com.juick.Message message = topEvent.getMessage();
- telegramService.getTelegramIdentifiers(Collections.singletonList(message.getUser()))
- .forEach(c -> telegramNotify(c, String.format("Your [post](%s) became popular!",
- formatUrl(message)), new com.juick.Message()));
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
- User subscriber = subscribeEvent.getUser();
- User target = subscribeEvent.getToUser();
- telegramService.getTelegramIdentifiers(Collections.singletonList(target))
- .forEach(c -> telegramNotify(c, String.format("%s subscribed to your blog",
- MessageUtils.getMarkdownUser(subscriber)), new com.juick.Message()));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/TopManager.java b/juick-server/src/main/java/com/juick/server/TopManager.java
deleted file mode 100644
index e5c00242..00000000
--- a/juick-server/src/main/java/com/juick/server/TopManager.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.service.MessagesService;
-import com.juick.service.component.TopEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import javax.inject.Inject;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Component
-public class TopManager {
- private static Logger logger = LoggerFactory.getLogger(TopManager.class);
- @Inject
- private MessagesService messagesService;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- @Scheduled(fixedRate = 3600000)
- public void updateTop() {
- messagesService.getPopularCandidates().forEach(m -> {
- Message jmsg = messagesService.getMessage(m);
- logger.info("added {} to popular", m);
- messagesService.setMessagePopular(m, 1);
- List<String> tags = jmsg.getTags().stream().map(Tag::getName).map(String::toLowerCase).collect(Collectors.toList());
- if (!tags.contains("juick")) {
- applicationEventPublisher.publishEvent(new TopEvent(this, jmsg));
- }
- });
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/TwitterManager.java b/juick-server/src/main/java/com/juick/server/TwitterManager.java
deleted file mode 100644
index 613594e6..00000000
--- a/juick-server/src/main/java/com/juick/server/TwitterManager.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.service.UserService;
-import com.juick.service.component.*;
-import com.juick.service.CrosspostService;
-import com.juick.util.MessageUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import twitter4j.TwitterFactory;
-import twitter4j.conf.ConfigurationBuilder;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-
-/**
- * @author Ugnich Anton
- */
-@Component
-public class TwitterManager implements NotificationListener {
-
- private static Logger logger = LoggerFactory.getLogger(TwitterManager.class);
-
- @Inject
- private CrosspostService crosspostService;
-
- @Value("${twitter_consumer_key:12345678}")
- private String twitter_consumer_key;
- @Value("${twitter_consumer_secret:secret}")
- private String twitter_consumer_secret;
- @Inject
- private UserService userService;
-
- @Value("${service_user:juick}")
- private String serviceUsername;
-
- private User serviceUser;
-
- @PostConstruct
- public void init() {
- serviceUser = userService.getUserByName(serviceUsername);
- }
-
- void twitterPost(final com.juick.Message jmsg) {
- crosspostService.getTwitterToken(jmsg.getUser().getUid()).ifPresent(t -> {
- String status = MessageUtils.getMessageHashTags(jmsg) + StringUtils.defaultString(jmsg.getText());
- if (status.length() > 253) {
- status = status.substring(0, 252) + "…";
- }
- status += " http://juick.com/" + jmsg.getMid();
- ConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
- .setDebugEnabled(true)
- .setOAuthConsumerKey(twitter_consumer_key)
- .setOAuthConsumerSecret(twitter_consumer_secret);
- TwitterFactory tf = new TwitterFactory(configurationBuilder
- .setOAuthAccessToken(t.getToken())
- .setOAuthAccessTokenSecret(t.getSecret()).build());
- try {
- tf.getInstance().updateStatus(status);
- } catch (Exception e) {
- logger.info("Twitter exception", e);
- }
- });
- }
-
- @Override
- public void processMessageEvent(MessageEvent messageEvent) {
- Message msg = messageEvent.getMessage();
- if (MessageUtils.isPM(msg) || MessageUtils.isReply(msg) || msg.isService()) {
- return;
- }
- if (StringUtils.isNotEmpty(crosspostService.getTwitterName(msg.getUser().getUid()))) {
- if (msg.getTags().stream().noneMatch(t -> t.getName().equals("notwitter"))) {
- twitterPost(msg);
- }
- }
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
-
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
-
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
-
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
- Message jmsg = topEvent.getMessage();
- jmsg.setUser(serviceUser);
- twitterPost(jmsg);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/Utils.java b/juick-server/src/main/java/com/juick/server/Utils.java
deleted file mode 100644
index 23768ed2..00000000
--- a/juick-server/src/main/java/com/juick/server/Utils.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Optional;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class Utils {
-
-
- public static String encodeSphinx(String str) {
- return str.replaceAll("@", "\\\\@")
- .replaceAll("\\'", "\\\\'")
- .replaceAll("=", "\\\\\\\\=");
- }
- /**
- * Returns the viewName to return for coming back to the sender url
- *
- * @param request Instance of {@link HttpServletRequest} or use an injected instance
- * @return Optional with the view name. Recomended to use an alternativa url with
- * {@link Optional#orElse(java.lang.Object)}
- */
- public static Optional<String> getPreviousPageByRequest(HttpServletRequest request)
- {
- return Optional.ofNullable(request.getHeader("Referer"));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/WebsocketManager.java b/juick-server/src/main/java/com/juick/server/WebsocketManager.java
deleted file mode 100644
index 1b62b984..00000000
--- a/juick-server/src/main/java/com/juick/server/WebsocketManager.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.model.CommandResult;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpHeaders;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-import org.springframework.web.socket.CloseStatus;
-import org.springframework.web.socket.PingMessage;
-import org.springframework.web.socket.TextMessage;
-import org.springframework.web.socket.WebSocketSession;
-import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
-import org.springframework.web.socket.handler.TextWebSocketHandler;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.time.Instant;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Created by vitalyster on 28.06.2016.
- */
-@Component
-public class WebsocketManager extends TextWebSocketHandler {
- private static final Logger logger = LoggerFactory.getLogger(WebsocketManager.class);
-
- private final List<UserSession> clients = new CopyOnWriteArrayList<>();
-
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private CommandsManager commandsManager;
-
-
- @Override
- public void afterConnectionEstablished(WebSocketSession session) {
-
- UserSession userSession = new UserSession(session);
- URI hLocation = session.getUri();
-
- // Auth
- UriComponents uriComponents = UriComponentsBuilder.fromUri(hLocation).build();
- List<String> hash = uriComponents.getQueryParams().get("hash");
- if (hash != null && hash.get(0).length() == 16) {
- userSession.visitor = userService.getUserByHash(hash.get(0));
- } else {
- logger.debug("wrong hash for {} from {}", userSession.visitor.getUid(), userSession);
- }
-
- if (hLocation.getPath().equals("/ws/")) {
- logger.debug("user {} connected", userSession.visitor.getUid());
- } else if (hLocation.getPath().equals("/ws/_all")) {
- logger.debug("user {} connected to legacy _all ({})", userSession.visitor.getUid(), hLocation.getPath());
- userSession.legacy = true;
- userSession.allMessages = true;
- } else if (hLocation.getPath().equals("/ws/_replies")) {
- logger.debug("user {} connected to legacy _replies ({})", userSession.visitor.getUid(), hLocation.getPath());
- userSession.legacy = true;
- userSession.allReplies = true;
- } else if (hLocation.getPath().matches("^/ws/(\\d)+$")) {
- int MID = NumberUtils.toInt(hLocation.getPath().substring(4), 0);
- if (MID > 0) {
- if (messagesService.canViewThread(MID, userSession.visitor.getUid())) {
- logger.debug("user {} connected to legacy thread ({}) from {}", userSession.visitor.getUid(), MID, userSession);
- userSession.legacy = true;
- userSession.MID = MID;
- } else {
- throw new HttpForbiddenException();
- }
- }
- } else {
- throw new HttpNotFoundException();
- }
- clients.add(userSession);
- logger.debug("{} clients connected", clients.size());
- }
-
- @Override
- public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
- logger.debug("session closed with status {}: {}", status.getCode(), status.getReason());
- clients.removeIf(c -> c.getDelegate().getId().equals(session.getId()));
- logger.debug("{} clients connected", clients.size());
- }
-
- @Scheduled(fixedRate = 30000)
- public void ping() {
- clients.forEach(c -> {
- try {
- if (c.isOpen()) {
- c.sendMessage(new PingMessage());
- }
- } catch (IOException e) {
- logger.error("WebSocket PING exception", e);
- }
- });
- }
-
- @Override
- protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
- UserSession ws = clients.stream().filter(c -> c.getDelegate().equals(session))
- .findFirst().orElseThrow(IllegalStateException::new);
- if (!ws.visitor.isAnonymous()) {
- String command = message.getPayload().trim();
- if (StringUtils.isNotEmpty(command)) {
- CommandResult result = commandsManager.processCommand(ws.visitor, command, URI.create(""));
- ws.sendMessage(new TextMessage(result.getText()));
- }
- } else {
- ws.sendMessage(new TextMessage("Authorization required"));
- }
- }
-
- public List<UserSession> getClients() {
- return clients;
- }
-
- class UserSession extends ConcurrentWebSocketSessionDecorator {
- User visitor;
- int MID;
- boolean allMessages;
- boolean allReplies;
- Instant tsConnected;
- Instant tsLastData;
- boolean legacy;
-
- UserSession(WebSocketSession session) {
- super(session, 60000, 65536);
- this.visitor = AnonymousUser.INSTANCE;
- tsConnected = tsLastData = Instant.now();
- }
-
- @Nonnull
- @Override
- public String toString() {
- HttpHeaders headers = getHandshakeHeaders();
- return headers.getOrDefault("X-Real-IP",
- Collections.singletonList(getRemoteAddress().toString())).get(0);
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/XMPPConnection.java b/juick-server/src/main/java/com/juick/server/XMPPConnection.java
deleted file mode 100644
index 9c0c09e1..00000000
--- a/juick-server/src/main/java/com/juick/server/XMPPConnection.java
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.User;
-import com.juick.formatters.PlainTextFormatter;
-import com.juick.service.component.*;
-import com.juick.model.CommandResult;
-import com.juick.model.UserInfo;
-import com.juick.server.xmpp.iq.MessageQuery;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import com.juick.server.xmpp.s2s.StanzaListener;
-import com.juick.service.*;
-import com.juick.util.MessageUtils;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.XmppException;
-import rocks.xmpp.core.session.XmppSession;
-import rocks.xmpp.core.stanza.AbstractIQHandler;
-import rocks.xmpp.core.stanza.model.*;
-import rocks.xmpp.core.stanza.model.client.ClientMessage;
-import rocks.xmpp.core.stanza.model.client.ClientPresence;
-import rocks.xmpp.core.stanza.model.errors.Condition;
-import rocks.xmpp.extensions.caps.EntityCapabilitiesManager;
-import rocks.xmpp.extensions.component.accept.ExternalComponent;
-import rocks.xmpp.extensions.disco.ServiceDiscoveryManager;
-import rocks.xmpp.extensions.disco.model.info.Identity;
-import rocks.xmpp.extensions.filetransfer.FileTransfer;
-import rocks.xmpp.extensions.filetransfer.FileTransferManager;
-import rocks.xmpp.extensions.nick.model.Nickname;
-import rocks.xmpp.extensions.oob.model.x.OobX;
-import rocks.xmpp.extensions.ping.PingManager;
-import rocks.xmpp.extensions.receipts.MessageDeliveryReceiptsManager;
-import rocks.xmpp.extensions.vcard.temp.model.VCard;
-import rocks.xmpp.extensions.version.SoftwareVersionManager;
-import rocks.xmpp.extensions.version.model.SoftwareVersion;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-/**
- * @author ugnich
- */
-public class XMPPConnection implements StanzaListener, NotificationListener {
-
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
-
- private ExternalComponent router;
- @Inject
- private XMPPServer xmpp;
- @Inject
- private CommandsManager commandsManager;
- @Value("${xmppbot_jid:juick@localhost}")
- private Jid jid;
- @Value("${componentname:localhost}")
- private String componentName;
- @Value("${component_port:5347}")
- private int componentPort;
- @Value("${xmpp_password:secret}")
- private String password;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
-
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private SubscriptionService subscriptionService;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private BasicXmppSession session;
- @Inject
- private ExecutorService service;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Value("${service_user:juick}")
- private String serviceUsername;
-
- private User serviceUser;
-
- @PostConstruct
- public void init() {
- logger.info("stream router start connecting to {}", componentPort);
- xmpp.addStanzaListener(this);
- router = ExternalComponent.create(componentName, password, session.getConfiguration(), "localhost", componentPort);
- ServiceDiscoveryManager serviceDiscoveryManager = router.getManager(ServiceDiscoveryManager.class);
- serviceDiscoveryManager.addIdentity(Identity.clientBot().withName("Juick"));
- EntityCapabilitiesManager entityCapabilitiesManager = router.getManager(EntityCapabilitiesManager.class);
- entityCapabilitiesManager.setNode("https://juick.com/caps");
- MessageDeliveryReceiptsManager messageDeliveryReceiptsManager = router.getManager(MessageDeliveryReceiptsManager.class);
- messageDeliveryReceiptsManager.setEnabled(true);
- PingManager pingManager = router.getManager(PingManager.class);
- pingManager.setEnabled(true);
- SoftwareVersionManager softwareVersionManager = router.getManager(SoftwareVersionManager.class);
- softwareVersionManager.setSoftwareVersion(new SoftwareVersion("Juick", "2.x",
- System.getProperty("os.name", "generic")));
- VCard vCard = new VCard();
- vCard.setFormattedName("Juick");
- vCard.setBirthday(LocalDate.of(2008, 10, 22));
- try {
- vCard.setUrl(new URL("http://juick.com/"));
- vCard.setPhoto(new VCard.Image("image/png", IOUtils.toByteArray(
- getClass().getClassLoader().getResource("juick.png"))));
- } catch (MalformedURLException e) {
- logger.error("invalid url", e);
- } catch (IOException e) {
- logger.warn("invalid resource", e);
- }
- router.addIQHandler(MessageQuery.class, iq -> {
- Message warningMessage = new Message(iq.getFrom(), Message.Type.CHAT);
- warningMessage.setFrom(jid);
- warningMessage.setBody("Your XMPP client constantly polls us with XMPP query which is unsupported for years, please find http://juick.com/query#messages in your client code and remove that");
- router.send(warningMessage);
- return iq.createError(new StanzaError(Condition.BAD_REQUEST, "Please stop this spam"));
- });
- router.addIQHandler(VCard.class, new AbstractIQHandler(IQ.Type.GET) {
- @Override
- protected IQ processRequest(IQ iq) {
- if (iq.getTo().equals(jid) || iq.getTo().asBareJid().equals(jid.asBareJid())
- || iq.getTo().asBareJid().toEscapedString().equals(jid.getDomain())) {
- return iq.createResult(vCard);
- }
- User user = userService.getUserByName(iq.getTo().getLocal());
- if (!user.isAnonymous()) {
- UserInfo info = userService.getUserInfo(user);
- VCard userVCard = new VCard();
- userVCard.setFormattedName(info.getFullName());
- userVCard.setNickname(user.getName());
- try {
- userVCard.setPhoto(new VCard.Image(new URI("http://i.juick.com/a/" + user.getUid() + ".png")));
- if (info.getUrl() != null) {
- userVCard.setUrl(new URL(info.getUrl()));
- }
- } catch (MalformedURLException | URISyntaxException e) {
- logger.warn("url exception", e);
- }
- return iq.createResult(userVCard);
- }
- return iq.createError(Condition.BAD_REQUEST);
- }
- });
- router.addInboundMessageListener(e -> {
- ClientMessage result = incomingMessage(e.getMessage());
- if (result != null) {
- router.send(result);
- }
- });
- router.addInboundIQListener(e -> {
- IQ iq = e.getIQ();
- Jid jid = iq.getTo();
- if (!jid.getDomain().equals(this.jid.getDomain())) {
- router.send(iq);
- }
- });
- FileTransferManager fileTransferManager = router.getManager(FileTransferManager.class);
- fileTransferManager.addFileTransferOfferListener(e -> {
- try {
- List<String> allowedTypes = new ArrayList<String>() {{
- add("png");
- add("jpg");
- }};
- String attachmentExtension = FilenameUtils.getExtension(e.getName()).toLowerCase();
- String targetFilename = String.format("%s.%s",
- DigestUtils.md5Hex(String.format("%s-%s",
- e.getInitiator().toString(), e.getSessionId()).getBytes()), attachmentExtension);
- if (allowedTypes.contains(attachmentExtension)) {
- Path filePath = Paths.get(tmpDir, targetFilename);
- FileTransfer ft = e.accept(filePath).get();
- ft.addFileTransferStatusListener(st -> {
- logger.debug("{}: received {} of {}", e.getName(), st.getBytesTransferred(), e.getSize());
- if (st.getStatus().equals(FileTransfer.Status.COMPLETED)) {
- logger.info("transfer completed");
- try {
- Jid initiator = e.getInitiator();
- ClientMessage result = incomingMessageJuick(
- userService.getUserByJID(initiator.asBareJid().toEscapedString()), initiator,
- e.getDescription(), URI.create(String.format("juick://%s", targetFilename)));
- if (result != null) {
- router.send(result);
- }
- } catch (Exception e1) {
- logger.error("ft error", e1);
- }
-
- } else if (st.getStatus().equals(FileTransfer.Status.FAILED)) {
- logger.info("transfer failed", ft.getException());
- Message msg = new Message();
- msg.setType(Message.Type.CHAT);
- msg.setFrom(jid);
- msg.setTo(e.getInitiator());
- msg.setBody("File transfer failed, please report to us");
- router.sendMessage(msg);
- } else if (st.getStatus().equals(FileTransfer.Status.CANCELED)) {
- logger.info("transfer cancelled");
- }
- });
- ft.transfer();
- logger.info("transfer started");
- } else {
- e.reject();
- logger.info("transfer rejected");
- }
- } catch (IOException | InterruptedException | ExecutionException e1) {
- logger.error("ft error", e1);
- }
- });
- router.addConnectionListener(event -> {
- if (event.getType().equals(rocks.xmpp.core.session.ConnectionEvent.Type.RECONNECTION_SUCCEEDED)) {
- logger.info("component connected");
- }
- });
- router.addSessionStatusListener(event -> {
- logger.info("event: " + event.getStatus(), event.getThrowable());
- if (event.getStatus().equals(XmppSession.Status.AUTHENTICATED)) {
- logger.info("Authenticated, broadcasting...");
- broadcastPresence(null);
- }
- });
- router.addInboundPresenceListener(event -> {
- incomingPresence(event.getPresence());
- });
- service.submit(() -> {
- try {
- router.connect();
- } catch (XmppException e) {
- logger.warn("xmpp exception", e);
- }
- });
- serviceUser = userService.getUserByName(serviceUsername);
- }
-
- private String stanzaToString(Stanza stanza) throws XMLStreamException, JAXBException {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- router.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- router.createMarshaller().marshal(stanza, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- return stanzaWriter.toString();
- }
-
- private void sendJuickMessage(com.juick.Message jmsg, List<User> users) {
- List<String> jids = new ArrayList<>();
-
- for (User user : users) {
- jids.addAll(userService.getJIDsbyUID(user.getUid()));
- }
- com.juick.Message fullMsg = messagesService.getMessage(jmsg.getMid());
- String txt = "@" + jmsg.getUser().getName() + ":" + MessageUtils.getTagsString(fullMsg) + "\n";
- String attachmentUrl = MessageUtils.attachmentUrl(fullMsg);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n";
- txt += "#" + jmsg.getMid() + " http://juick.com/m/" + jmsg.getMid();
-
- Nickname nick = new Nickname("@" + jmsg.getUser().getName());
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.setThread("juick-" + jmsg.getMid());
- msg.addExtension(jmsg);
- msg.addExtension(nick);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- try {
- OobX oob = new OobX(new URI(attachmentUrl));
- msg.addExtension(oob);
- } catch (URISyntaxException e) {
- logger.warn("uri exception", e);
- }
- }
- for (String jid : jids) {
- msg.setTo(Jid.of(jid));
- router.send(ClientMessage.from(msg));
- }
- }
-
- public void sendJuickComment(com.juick.Message jmsg, List<User> users) {
- String replyQuote;
- String replyTo;
-
- com.juick.Message replyMessage = jmsg.getReplyto() > 0 ? messagesService.getReply(jmsg.getMid(), jmsg.getReplyto())
- : messagesService.getMessage(jmsg.getMid());
- replyTo = replyMessage.getUser().getName();
- com.juick.Message fullReply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- replyQuote = StringUtils.defaultString(fullReply.getReplyQuote());
-
- String txt = "Reply by @" + jmsg.getUser().getName() + ":\n" + replyQuote + "\n@" + replyTo + " ";
- String attachmentUrl = MessageUtils.attachmentUrl(fullReply);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n" + "#" + jmsg.getMid() + "/" + jmsg.getRid() + " http://juick.com/m/" + jmsg.getMid() + "#" + jmsg.getRid();
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.addExtension(jmsg);
- for (User user : users) {
- for (String jid : userService.getJIDsbyUID(user.getUid())) {
- msg.setTo(Jid.of(jid));
- router.send(ClientMessage.from(msg));
- }
- }
- }
-
- @Override
- public void processMessageEvent(MessageEvent event) {
- com.juick.Message msg = event.getMessage();
- List<User> subscribers = event.getUsers();
- if (msg.isService()) {
- return;
- }
- if (MessageUtils.isPM(msg)) {
- userService.getJIDsbyUID(msg.getTo().getUid())
- .forEach(userJid -> {
- Message mm = new Message();
- mm.setTo(Jid.of(userJid));
- mm.setType(Message.Type.CHAT);
- boolean inroster = pmQueriesService.havePMinRoster(msg.getUser().getUid(), userJid);
- if (inroster) {
- mm.setFrom(Jid.of(msg.getUser().getName(), "juick.com", "Juick"));
- mm.setBody(msg.getText());
- } else {
- mm.setFrom(jid);
- mm.setBody("Private message from @" + msg.getUser().getName() + ":\n" + msg.getText());
- }
- router.send(ClientMessage.from(mm));
- });
- } else if (MessageUtils.isReply(msg)) {
- sendJuickComment(msg, subscribers);
- }
- else {
- sendJuickMessage(msg, subscribers);
- }
- }
-
- private ClientMessage makeReply(Jid jidTo, String txt) {
- Message reply = new Message();
- reply.setFrom(jid);
- reply.setTo(jidTo);
- reply.setType(Message.Type.CHAT);
- reply.setBody(txt);
- return ClientMessage.from(reply);
- }
-
- @Override
- public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
-
- }
-
- @Override
- public void processLikeEvent(LikeEvent likeEvent) {
- List<User> users = likeEvent.getSubscribers();
- com.juick.Message jmsg = likeEvent.getMessage();
- User liker = likeEvent.getUser();
-
- if (!userService.isInBLAny(jmsg.getUser().getUid(), liker.getUid())) {
- userService.getJIDsbyUID(jmsg.getUser().getUid()).forEach(authorJid -> {
- Message xmppMessage = new Message();
- xmppMessage.setFrom(jid);
- xmppMessage.setTo(Jid.of(authorJid));
- xmppMessage.setType(Message.Type.CHAT);
- xmppMessage.addExtension(jmsg);
- xmppMessage.setBody(String.format("%s recommended your post #%d. %s",
- liker.getName(), jmsg.getMid(), PlainTextFormatter.formatUrl(jmsg)));
- router.send(ClientMessage.from(xmppMessage));
- });
- }
-
- String txt = "Recommended by @" + liker.getName() + ":\n";
- txt += "@" + jmsg.getUser().getName() + ":" + MessageUtils.getTagsString(jmsg) + "\n";
- String attachmentUrl = MessageUtils.attachmentUrl(jmsg);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- txt += attachmentUrl + "\n";
- }
- txt += StringUtils.defaultString(jmsg.getText()) + "\n\n";
- txt += "#" + jmsg.getMid();
- if (jmsg.getReplies() > 0) {
- if (jmsg.getReplies() % 10 == 1 && jmsg.getReplies() % 100 != 11) {
- txt += " (" + jmsg.getReplies() + " reply)";
- } else {
- txt += " (" + jmsg.getReplies() + " replies)";
- }
- }
- txt += " http://juick.com/m/" + jmsg.getMid();
-
- Nickname nick = new Nickname("@" + jmsg.getUser().getName());
-
- Message msg = new Message();
- msg.setFrom(jid);
- msg.setBody(txt);
- msg.setType(Message.Type.CHAT);
- msg.setThread("juick-" + jmsg.getMid());
- msg.addExtension(jmsg);
- msg.addExtension(nick);
- if (StringUtils.isNotEmpty(attachmentUrl)) {
- try {
- OobX oob = new OobX(new URI(attachmentUrl));
- msg.addExtension(oob);
- } catch (URISyntaxException e) {
- logger.warn("uri exception", e);
- }
- }
-
- for (User user : users) {
- for (String jid : userService.getJIDsbyUID(user.getUid())) {
- msg.setTo(Jid.of(jid));
- router.send(ClientMessage.from(msg));
- }
- }
- }
-
- @Override
- public void processPingEvent(PingEvent pingEvent) {
- userService.getJIDsbyUID(pingEvent.getPinger().getUid())
- .forEach(userJid -> {
- Presence p = new Presence(Jid.of(userJid));
- p.setFrom(jid);
- p.setPriority((byte) 10);
- router.send(ClientPresence.from(p));
- });
- }
-
- @Override
- public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
-
- }
-
- @Override
- public void processTopEvent(TopEvent topEvent) {
- com.juick.Message message = topEvent.getMessage();
- try {
- commandsManager.processCommand(serviceUser, String.format("! #%d", message.getMid()), URI.create(StringUtils.EMPTY));
- } catch (Exception e) {
- logger.warn("XMPP error", e);
- }
- }
-
- private void incomingPresence(Presence p) {
- final String username = p.getTo().getLocal();
- final boolean toJuick = username.equals(jid.getLocal());
-
- if (p.getType() == null) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo().asBareJid());
- reply.setTo(p.getFrom().asBareJid());
- reply.setType(Presence.Type.UNSUBSCRIBE);
- router.send(ClientPresence.from(reply));
- } else if (p.getType().equals(Presence.Type.PROBE)) {
- int uid_to = 0;
- if (!toJuick) {
- uid_to = userService.getUIDbyName(username);
- } else {
- User visitor = userService.getUserByJID(p.getFrom().asBareJid().toEscapedString());
- if (visitor != null) {
- userService.updateLastSeen(visitor);
- }
- }
-
- if (toJuick || uid_to > 0) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo().withResource(jid.getResource()));
- reply.setTo(p.getFrom());
- reply.setPriority((byte)10);
- if (!userService.getActiveJIDs().contains(p.getFrom().asBareJid().toEscapedString())) {
- reply.setStatus("Send ON to enable notifications");
- }
- router.send(ClientPresence.from(reply));
- } else {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.ERROR);
- reply.setId(p.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
- router.send(ClientPresence.from(reply));
- }
- } else if (p.getType().equals(Presence.Type.SUBSCRIBE)) {
- boolean canSubscribe = false;
- if (toJuick) {
- canSubscribe = true;
- } else {
- int uid_to = userService.getUIDbyName(username);
- if (uid_to > 0) {
- pmQueriesService.addPMinRoster(uid_to, p.getFrom().asBareJid().toEscapedString());
- canSubscribe = true;
- }
- }
- if (canSubscribe) {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.SUBSCRIBED);
- router.send(ClientPresence.from(reply));
-
- reply.setFrom(reply.getFrom().withResource(jid.getResource()));
- reply.setPriority((byte) 10);
- reply.setType(null);
- router.send(ClientPresence.from(reply));
- } else {
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.ERROR);
- reply.setId(p.getId());
- reply.setError(new StanzaError(StanzaError.Type.CANCEL, Condition.ITEM_NOT_FOUND));
- router.send(ClientPresence.from(reply));
- }
- } else if (p.getType().equals(Presence.Type.UNSUBSCRIBE)) {
- if (!toJuick) {
- int uid_to = userService.getUIDbyName(username);
- if (uid_to > 0) {
- pmQueriesService.removePMinRoster(uid_to, p.getFrom().asBareJid().toEscapedString());
- }
- }
-
- Presence reply = new Presence();
- reply.setFrom(p.getTo());
- reply.setTo(p.getFrom());
- reply.setType(Presence.Type.UNSUBSCRIBED);
- router.send(ClientPresence.from(reply));
- }
- }
-
- public ClientMessage incomingMessage(Message msg) {
- ClientMessage result = null;
- if (msg.getType() != null && msg.getType().equals(Message.Type.ERROR)) {
- StanzaError error = msg.getError();
- if (error != null && error.getCondition().equals(Condition.RESOURCE_CONSTRAINT)) {
- // offline query is full, deactivating this jid
- if (userService.setActiveStatusForJID(msg.getFrom().toEscapedString(), UserService.ActiveStatus.Inactive)) {
- logger.info("{} is inactive now", msg.getFrom());
- return null;
- }
- }
- return null;
- }
- Jid to = msg.getTo();
- if (to.getDomain().equals(router.getDomain().toEscapedString()) || to.equals(this.jid)) {
- User user_from = userService.getUserByJID(msg.getFrom().asBareJid().toEscapedString());
- if ((user_from == null || user_from.isAnonymous()) && !msg.getFrom().equals(jid)) {
- String signuphash = userService.getSignUpHashByJID(msg.getFrom().asBareJid().toEscapedString());
- return makeReply(msg.getFrom(), "Для того, чтобы начать пользоваться сервисом, пожалуйста пройдите быструю регистрацию: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nЕсли у вас уже есть учетная запись на Juick, вы сможете присоединить этот JabberID к ней.\n\nTo start using Juick, please sign up: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nIf you already have an account on Juick, you will be proposed to attach this JabberID to your existing account.");
- }
-
- com.juick.Message jmsg = msg.getExtension(com.juick.Message.class);
- if (jmsg != null) {
- if (MessageUtils.isReply(jmsg)) {
- // to get quote and attachment
- com.juick.Message original = messagesService.getMessage(jmsg.getMid());
- com.juick.Message reply = messagesService.getReply(jmsg.getMid(), jmsg.getRid());
- applicationEventPublisher.publishEvent(new MessageEvent(this, reply,
- subscriptionService.getUsersSubscribedToComments(original, reply)));
- } else if (!MessageUtils.isPM(jmsg)) {
- applicationEventPublisher.publishEvent(new MessageEvent(this,
- messagesService.getMessage(jmsg.getMid()), subscriptionService.getSubscribedUsers(jmsg.getUser().getUid(), jmsg)));
- }
- } else {
- URI attachment = URI.create(StringUtils.EMPTY);
- OobX oobX = msg.getExtension(OobX.class);
- if (oobX != null) {
- attachment = oobX.getUri();
- }
- try {
- if (msg.getTo().asBareJid().equals(jid.asBareJid())) {
- return incomingMessageJuick(user_from, msg.getFrom(), StringUtils.defaultString(msg.getBody()), attachment);
- } else {
- // PM
- result = incomingMessageJuick(user_from, msg.getFrom(),
- String.format("@%s %s", msg.getTo().getLocal(), StringUtils.defaultString(msg.getBody())), attachment);
- }
- } catch (Exception e1) {
- logger.warn("message exception", e1);
- }
- }
- } else if (to.getDomain().endsWith(jid.getDomain()) && (to.getDomain().equals(jid.getDomain())
- || to.getDomain().endsWith("." + jid.getDomain()))) {
- if (logger.isInfoEnabled()) {
- try {
- logger.info("unhandled message: {}", stanzaToString(msg));
- } catch (JAXBException | XMLStreamException ex) {
- logger.error("JAXB exception", ex);
- }
- }
- } else {
- return ClientMessage.from(msg);
- }
- return result;
- }
- private ClientMessage incomingMessageJuick(User user_from, Jid from, String command, @Nonnull URI attachment) {
- if (StringUtils.isBlank(command) && attachment.toString().isEmpty()) {
- return null;
- }
-
- int commandlen = command.length();
-
- // COMPATIBILITY
- if (commandlen > 7 && command.substring(0, 3).equalsIgnoreCase("PM ")) {
- command = command.substring(3);
- }
-
- try {
- CommandResult result = commandsManager.processCommand(user_from, command.trim(), attachment);
- if (StringUtils.isNotBlank(result.getText())) {
- return makeReply(from, result.getText());
- }
- } catch (Exception e) {
- logger.warn("xmpp command exception", e);
- return makeReply(from, "Error processing command");
- }
- return null;
- }
-
- @Override
- public void stanzaReceived(Stanza xmlValue) {
- router.send(xmlValue);
- }
-
- private void broadcastPresence(Presence.Type type) {
- Presence presence = new Presence();
- presence.setFrom(jid);
- if (type != null) {
- presence.setType(type);
- }
- userService.getActiveJIDs().forEach(j -> {
- try {
- presence.setTo(Jid.of(j));
- router.send(ClientPresence.from(presence));
- } catch (IllegalArgumentException ex) {
- logger.warn("Invalid jid: {}", j, ex);
- }
- });
- }
-
- @PreDestroy
- public void close() throws Exception {
- broadcastPresence(Presence.Type.UNAVAILABLE);
- if (router != null) {
- router.close();
- }
- }
-
- public ExternalComponent getRouter() {
- return router;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/XMPPServer.java b/juick-server/src/main/java/com/juick/server/XMPPServer.java
deleted file mode 100644
index 86ab6a78..00000000
--- a/juick-server/src/main/java/com/juick/server/XMPPServer.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server;
-
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.s2s.*;
-import com.juick.service.UserService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.Stanza;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.net.ssl.*;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import java.io.IOException;
-import java.io.StringReader;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.SecureRandom;
-import java.security.cert.*;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @author ugnich
- */
-public class XMPPServer implements ConnectionListener {
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
-
- private static final int TIMEOUT_MINUTES = 15;
-
- @Inject
- public ExecutorService service;
- @Value("${hostname:localhost}")
- private Jid jid;
- @Value("${s2s_port:5269}")
- private int s2sPort;
- @Value("${broken_ssl_hosts:}")
- public String[] brokenSSLhosts;
- @Value("${banned_hosts:}")
- public String[] bannedHosts;
-
- private final List<ConnectionIn> inConnections = new CopyOnWriteArrayList<>();
- private final Map<ConnectionOut, Optional<Socket>> outConnections = new ConcurrentHashMap<>();
- private final List<CacheEntry> outCache = new CopyOnWriteArrayList<>();
- private final List<StanzaListener> stanzaListeners = new CopyOnWriteArrayList<>();
- private final AtomicBoolean closeFlag = new AtomicBoolean(false);
-
- SSLContext sc;
- CertificateFactory cf;
- CertPathValidator cpv;
- PKIXParameters params;
- private TrustManager[] trustAllCerts = new TrustManager[]{
- new X509TrustManager() {
- public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
- }
-
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }
- };
- private boolean tlsConfigured = false;
-
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
- @Inject
- private UserService userService;
- @Inject
- private KeystoreManager keystoreManager;
-
- @PostConstruct
- public void init() throws KeyStoreException {
- closeFlag.set(false);
- try {
- sc = SSLContext.getInstance("TLSv1.2");
- sc.init(keystoreManager.getKeymanagerFactory().getKeyManagers(), trustAllCerts, new SecureRandom());
- TrustManagerFactory trustManagerFactory =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- Set<TrustAnchor> ca = new HashSet<>();
- trustManagerFactory.init((KeyStore)null);
- Arrays.stream(trustManagerFactory.getTrustManagers()).forEach(t -> Arrays.stream(((X509TrustManager)t).getAcceptedIssuers()).forEach(cert -> ca.add(new TrustAnchor(cert, null))));
- params = new PKIXParameters(ca);
- params.setRevocationEnabled(false);
- cpv = CertPathValidator.getInstance("PKIX");
- cf = CertificateFactory.getInstance( "X.509" );
- tlsConfigured = true;
- } catch (Exception e) {
- logger.warn("tls unavailable");
- }
- service.submit(() -> {
- try {
- listener = new ServerSocket(s2sPort);
- logger.info("s2s listener ready");
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- ConnectionIn client = new ConnectionIn(this, socket);
- addConnectionIn(client);
- service.submit(client);
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException | XmlPullParserException e) {
- logger.warn("xmpp exception", e);
- }
- });
- }
-
- public void addConnectionIn(ConnectionIn c) {
- c.setListener(this);
- inConnections.add(c);
- }
-
- public void addConnectionOut(ConnectionOut c, Optional<Socket> socket) {
- c.setListener(this);
- outConnections.put(c, socket);
- }
-
- public void removeConnectionIn(ConnectionIn c) {
- inConnections.remove(c);
- }
-
- public void removeConnectionOut(ConnectionOut c) {
- outConnections.remove(c);
- }
-
- public String getFromCache(Jid to) {
- final String[] cache = new String[1];
- outCache.stream().filter(c -> c.hostname != null && c.hostname.equals(to)).findFirst().ifPresent(c -> {
- cache[0] = c.xml;
- outCache.remove(c);
- });
- return cache[0];
- }
-
- public Optional<ConnectionOut> getConnectionOut(Jid hostname, boolean needReady) {
- return outConnections.keySet().stream().filter(c -> c.to != null &&
- c.to.equals(hostname) && (!needReady || c.streamReady)).findFirst();
- }
-
- public Optional<ConnectionIn> getConnectionIn(String streamID) {
- return inConnections.stream().filter(c -> c.streamID != null && c.streamID.equals(streamID)).findFirst();
- }
-
- public void sendOut(Jid hostname, String xml) {
- boolean haveAnyConn = false;
-
- ConnectionOut connOut = null;
- for (ConnectionOut c : outConnections.keySet()) {
- if (c.to != null && c.to.equals(hostname)) {
- if (c.streamReady) {
- connOut = c;
- break;
- } else {
- haveAnyConn = true;
- break;
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
-
- boolean haveCache = false;
- for (CacheEntry c : outCache) {
- if (c.hostname != null && c.hostname.equals(hostname)) {
- c.xml += xml;
- c.updated = Instant.now();
- haveCache = true;
- break;
- }
- }
- if (!haveCache) {
- outCache.add(new CacheEntry(hostname, xml));
- }
-
- if (!haveAnyConn && !closeFlag.get()) {
- try {
- createDialbackConnection(hostname.toEscapedString(), null, null);
- } catch (Exception e) {
- logger.warn("dialback error", e);
- }
- }
- }
-
- void createDialbackConnection(String to, String checkSID, String dbKey) throws Exception {
- ConnectionOut connectionOut = new ConnectionOut(getJid(), Jid.of(to), null, null, checkSID, dbKey);
- addConnectionOut(connectionOut, Optional.empty());
- service.submit(() -> {
- try {
- Socket socket = new Socket();
- socket.connect(DNSQueries.getServerAddress(to));
- connectionOut.setInputStream(socket.getInputStream());
- connectionOut.setOutputStream(socket.getOutputStream());
- addConnectionOut(connectionOut, Optional.of(socket));
- connectionOut.connect();
- } catch (IOException e) {
- logger.info("dialback to " + to + " exception", e);
- }
- });
- }
-
- public void startDialback(Jid from, String streamId, String dbKey) throws Exception {
- Optional<ConnectionOut> c = getConnectionOut(from, false);
- if (c.isPresent()) {
- c.get().sendDialbackVerify(streamId, dbKey);
- } else {
- createDialbackConnection(from.toEscapedString(), streamId, dbKey);
- }
- }
-
- public void addStanzaListener(StanzaListener listener) {
- stanzaListeners.add(listener);
- }
-
- public void onStanzaReceived(String xmlValue) {
- logger.info("S2S: {}", xmlValue);
- Stanza stanza = parse(xmlValue);
- stanzaListeners.forEach(l -> l.stanzaReceived(stanza));
- }
-
- public BasicXmppSession getSession() {
- return session;
- }
-
- public List<ConnectionIn> getInConnections() {
- return inConnections;
- }
-
- public Map<ConnectionOut, Optional<Socket>> getOutConnections() {
- return outConnections;
- }
-
- @Override
- public boolean isTlsAvailable() {
- return tlsConfigured;
- }
-
- @Override
- public void starttls(ConnectionIn connection) {
- logger.debug("stream {} securing", connection.streamID);
- connection.sendStanza("<proceed xmlns=\"" + Connection.NS_TLS + "\" />");
- try {
- connection.setSocket(sc.getSocketFactory().createSocket(connection.getSocket(), connection.getSocket().getInetAddress().getHostAddress(),
- connection.getSocket().getPort(), false));
- SSLSocket sslSocket = (SSLSocket) connection.getSocket();
- sslSocket.addHandshakeCompletedListener(handshakeCompletedEvent -> {
- try {
- CertPath certPath = cf.generateCertPath(Arrays.asList(handshakeCompletedEvent.getPeerCertificates()));
- cpv.validate(certPath, params);
- connection.setTrusted(true);
- logger.info("connection from {} is trusted", connection.from);
- } catch (SSLPeerUnverifiedException | CertificateException | CertPathValidatorException | InvalidAlgorithmParameterException e) {
- logger.info("connection from {} is NOT trusted, falling back to dialback", connection.from);
- }
- });
- sslSocket.setUseClientMode(false);
- sslSocket.setNeedClientAuth(true);
- sslSocket.startHandshake();
- connection.setSecured(true);
- logger.debug("stream from {} secured", connection.streamID);
- connection.restartParser();
- } catch (XmlPullParserException | IOException sex) {
- logger.warn("stream {} ssl error {}", connection.streamID, sex);
- connection.sendStanza("<failure xmlns=\"" + Connection.NS_TLS + "\" />");
- removeConnectionIn(connection);
- connection.closeConnection();
- }
- }
-
- @Override
- public void proceed(ConnectionOut connection) {
- try {
- Socket socket = outConnections.get(connection).get();
- socket = sc.getSocketFactory().createSocket(socket, socket.getInetAddress().getHostAddress(),
- socket.getPort(), false);
- SSLSocket sslSocket = (SSLSocket) socket;
- sslSocket.addHandshakeCompletedListener(handshakeCompletedEvent -> {
- try {
- CertPath certPath = cf.generateCertPath(Arrays.asList(handshakeCompletedEvent.getPeerCertificates()));
- cpv.validate(certPath, params);
- connection.setTrusted(true);
- logger.info("connection to {} is trusted", connection.to);
- } catch (SSLPeerUnverifiedException | CertificateException | CertPathValidatorException | InvalidAlgorithmParameterException e) {
- logger.info("connection to {} is NOT trusted, falling back to dialback", connection.to);
- }
- });
- sslSocket.setNeedClientAuth(true);
- sslSocket.startHandshake();
- connection.setSecured(true);
- logger.debug("stream to {} secured", connection.getStreamID());
- connection.setInputStream(socket.getInputStream());
- connection.setOutputStream(socket.getOutputStream());
- connection.restartStream();
- connection.sendOpenStream();
- } catch (NoSuchElementException | XmlPullParserException | IOException sex) {
- logger.error("s2s ssl error: {} {}, error {}", connection.to, connection.getStreamID(), sex);
- connection.send("<failure xmlns=\"" + Connection.NS_TLS + "\" />");
- removeConnectionOut(connection);
- connection.logoff();
- }
- }
-
- @Override
- public void verify(ConnectionOut connection, String from, String type, String sid) {
- if (from != null && from.equals(connection.to.toEscapedString()) && sid != null && !sid.isEmpty() && type != null) {
- getConnectionIn(sid).ifPresent(c -> c.sendDialbackResult(Jid.of(from), type));
- }
- }
-
- @Override
- public void dialbackError(ConnectionOut connection, StreamError error) {
- logger.warn("Stream error from {}: {}", connection.getStreamID(), error.getCondition());
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void finished(ConnectionOut connection, boolean dirty) {
- logger.warn("stream to {} {} finished, dirty={}", connection.to, connection.getStreamID(), dirty);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void exception(ConnectionOut connection, Exception ex) {
- logger.error("s2s out exception: {} {}, exception {}", connection.to, connection.getStreamID(), ex);
- removeConnectionOut(connection);
- connection.logoff();
- }
-
- @Override
- public void ready(ConnectionOut connection) {
- logger.debug("stream to {} {} ready", connection.to, connection.getStreamID());
- String cache = getFromCache(connection.to);
- if (cache != null) {
- logger.debug("stream to {} {} sending cache", connection.to, connection.getStreamID());
- connection.send(cache);
- }
- }
-
- @Override
- public boolean securing(ConnectionOut connection) {
- return tlsConfigured && !Arrays.asList(brokenSSLhosts).contains(connection.to.toEscapedString());
- }
-
- public Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
-
- public Jid getJid() {
- return jid;
- }
- @Scheduled(fixedDelay = 10000)
- public void cleanUp() {
- Instant now = Instant.now();
- outConnections.keySet().stream().filter(c -> Duration.between(c.getUpdated(), now).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle outgoing connection to {}", c.to);
- c.logoff();
- outConnections.remove(c);
- });
-
- inConnections.stream().filter(c -> Duration.between(c.updated, now).toMinutes() > TIMEOUT_MINUTES)
- .forEach(c -> {
- logger.info("closing idle incoming connection from {}", c.from);
- c.closeConnection();
- inConnections.remove(c);
- });
- }
- @PreDestroy
- public void preDestroy() throws IOException {
- closeFlag.set(true);
- if (listener != null && !listener.isClosed()) {
- listener.close();
- }
- service.shutdown();
- logger.info("XMPP server destroyed");
- }
-
- public int getServerPort() {
- return s2sPort;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java b/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java
deleted file mode 100644
index 8d9f9402..00000000
--- a/juick-server/src/main/java/com/juick/server/api/ApiSocialLogin.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.api;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.scribejava.apis.FacebookApi;
-import com.github.scribejava.apis.VkontakteApi;
-import com.github.scribejava.core.builder.ServiceBuilder;
-import com.github.scribejava.core.model.OAuth2AccessToken;
-import com.github.scribejava.core.model.OAuthRequest;
-import com.github.scribejava.core.model.Verb;
-import com.github.scribejava.core.oauth.OAuth20Service;
-import com.juick.model.facebook.User;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.service.CrosspostService;
-import com.juick.service.EmailService;
-import com.juick.service.TelegramService;
-import com.juick.service.UserService;
-import com.juick.model.vk.UsersResponse;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Controller
-public class ApiSocialLogin {
-
- private static final Logger logger = LoggerFactory.getLogger(ApiSocialLogin.class);
-
- @Value("${facebook_appid:appid}")
- private String FACEBOOK_APPID;
- @Value("${facebook_secret:secret}")
- private String FACEBOOK_SECRET;
- private static final String FACEBOOK_REDIRECT = "https://api.juick.com/_fblogin";
- private static final String VK_REDIRECT = "https://api.juick.com/_vklogin";
- private static final String TWITTER_VERIFY_URL = "https://api.twitter.com/1.1/account/verify_credentials.json";
- @Inject
- private ObjectMapper jsonMapper;
- private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder;
-
- @Value("${twitter_consumer_key:appid}")
- private String twitterConsumerKey;
- @Value("${twitter_consumer_secret:secret}")
- private String twitterConsumerSecret;
- @Value("${vk_appid:appid}")
- private String VK_APPID;
- @Value("${vk_secret:secret}")
- private String VK_SECRET;
- @Value("${telegram_token:secret}")
- private String telegramToken;
-
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private UserService userService;
- @Inject
- private EmailService emailService;
- @Inject
- private TelegramService telegramService;
-
- @PostConstruct
- public void init() {
- facebookBuilder = new ServiceBuilder(FACEBOOK_APPID);
- twitterBuilder = new ServiceBuilder(twitterConsumerKey);
- vkBuilder = new ServiceBuilder(VK_APPID);
- }
-
- @GetMapping("/api/_fblogin")
- protected String doFacebookLogin(@RequestParam(required = false) String code,
- @RequestParam(required = false) String state) throws IOException, ExecutionException, InterruptedException {
- if (StringUtils.isBlank(code)) {
- String fbstate = UUID.randomUUID().toString();
- crosspostService.addFacebookState(fbstate, state);
- OAuth20Service facebookAuthService = facebookBuilder
- .apiSecret(FACEBOOK_SECRET)
- .callback(FACEBOOK_REDIRECT)
- .scope("email")
- .state(fbstate)
- .build(FacebookApi.instance());
- return "redirect:" + facebookAuthService.getAuthorizationUrl();
- }
-
- String redirectUrl = crosspostService.verifyFacebookState(state);
-
- if (StringUtils.isEmpty(redirectUrl)) {
- logger.error("state is missing");
- throw new HttpBadRequestException();
- }
- OAuth20Service facebookService = facebookBuilder
- .apiKey(FACEBOOK_APPID)
- .apiSecret(FACEBOOK_SECRET)
- .callback(FACEBOOK_REDIRECT)
- .scope("email")
- .state(state)
- .build(FacebookApi.instance());
- OAuth2AccessToken token = facebookService.getAccessToken(code);
- final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email");
- facebookService.signRequest(token, meRequest);
- String graph = facebookService.execute(meRequest).getBody();
- if (StringUtils.isBlank(graph)) {
- logger.error("FACEBOOK GRAPH ERROR");
- throw new HttpBadRequestException();
- }
- User fb = jsonMapper.readValue(graph, User.class);
- long fbID = NumberUtils.toLong(fb.getId(), 0);
- if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) {
- logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink());
- throw new HttpBadRequestException();
- }
-
- int uid = crosspostService.getUIDbyFBID(fbID);
- if (uid > 0) {
- if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) {
- logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken());
- throw new HttpBadRequestException();
- }
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl);
- uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid));
- return "redirect:" + uriComponentsBuilder.build().toUriString();
- } else if (fb.getVerified()) {
- if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) {
- if (StringUtils.isNotEmpty(fb.getEmail())) {
- logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink());
- Integer userId = crosspostService.getUIDbyFBID(fbID);
- if (!emailService.getEmails(userId, false).contains(fb.getEmail())) {
- emailService.addEmail(userId, fb.getEmail());
- }
- }
- logger.info("email not found for facebook user {}", fb.getLink());
- throw new HttpBadRequestException();
- }
- return "redirect:/signup?type=fb&hash=" + state;
- } else {
- logger.error("Facebook account is not verified, id: {}", fbID);
- throw new HttpBadRequestException();
- }
- }/*
- @GetMapping("/_twitter")
- protected void doTwitterLogin(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ExecutionException, InterruptedException {
- String hash = StringUtils.EMPTY, request_token = StringUtils.EMPTY, request_token_secret = StringUtils.EMPTY;
- String verifier = request.getParameter("oauth_verifier");
- Cookie[] cookies = request.getCookies();
- for (Cookie cookie : cookies) {
- if (cookie.getName().equals("hash")) {
- hash = cookie.getValue();
- }
- if (cookie.getName().equals("request_token")) {
- request_token = cookie.getValue();
- }
- if (cookie.getName().equals("request_token_secret")) {
- request_token_secret = cookie.getValue();
- }
- }
- com.juick.User user = UserUtils.getCurrentUser();
- OAuth10aService oAuthService = twitterBuilder
- .apiSecret(twitterConsumerSecret)
- .callback("http://juick.com/_twitter")
- .build(TwitterApi.instance());
-
- if (request_token.isEmpty() && request_token_secret.isEmpty()
- && (verifier == null || verifier.isEmpty())) {
- OAuth1RequestToken requestToken = oAuthService.getRequestToken();
- String authUrl = oAuthService.getAuthorizationUrl(requestToken);
- response.addCookie(new Cookie("request_token", requestToken.getToken()));
- response.addCookie(new Cookie("request_token_secret", requestToken.getTokenSecret()));
- response.setStatus(HttpServletResponse.SC_FOUND);
- response.setHeader("Location", authUrl);
- } else {
- if (verifier != null && verifier.length() > 0) {
- OAuth1RequestToken requestToken = new OAuth1RequestToken(request_token, request_token_secret);
- OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier);
- OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, TWITTER_VERIFY_URL);
- oAuthService.signRequest(accessToken, oAuthRequest);
- com.juick.twitter.User twitterUser = jsonMapper.readValue(oAuthService.execute(oAuthRequest).getBody(),
- com.juick.twitter.User.class);
- if (userService.linkTwitterAccount(user, accessToken.getToken(), accessToken.getTokenSecret(),
- twitterUser.getScreenName())) {
- response.setStatus(HttpServletResponse.SC_FOUND);
- response.setHeader("Location", "http://juick.com/settings");
- } else {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- }
- }
- }
- }*/
- @GetMapping("/api/_vklogin")
- protected String doVKLogin(@RequestParam(required = false) String code,
- @RequestParam String state) throws IOException, ExecutionException, InterruptedException {
- if (StringUtils.isBlank(code)) {
- String vkstate = UUID.randomUUID().toString();
- crosspostService.addVKState(vkstate, state);
- OAuth20Service vkAuthService = vkBuilder
- .apiSecret(VK_SECRET)
- .scope("friends,wall,offline")
- .state(vkstate)
- .callback(VK_REDIRECT)
- .build(VkontakteApi.instance());
- return "redirect:" + vkAuthService.getAuthorizationUrl();
- }
-
- String redirectUrl = crosspostService.verifyVKState(state);
- if (StringUtils.isBlank(redirectUrl)) {
- logger.error("state is missing");
- throw new HttpBadRequestException();
- }
-
- OAuth20Service vkService = vkBuilder
- .apiKey(VK_APPID)
- .apiSecret(VK_SECRET)
- .build(VkontakteApi.instance());
- OAuth2AccessToken token = vkService.getAccessToken(code);
-
- OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73");
- vkService.signRequest(token, meRequest);
- String graph = vkService.execute(meRequest).getBody();
-
- com.juick.model.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0);
- String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName();
- String vkLink = jsonUser.getScreenName();
-
- if (vkName.length() == 1 || StringUtils.isBlank(vkLink)) {
- logger.error("vk user error");
- throw new HttpBadRequestException();
- }
-
- Long vkID = NumberUtils.toLong(jsonUser.getId(), 0);
- int uid = crosspostService.getUIDbyVKID(vkID);
- if (uid > 0) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(redirectUrl);
- uriComponentsBuilder.queryParam("hash", userService.getHashByUID(uid));
- return "redirect:" + uriComponentsBuilder.build().toUriString();
- } else {
- String loginhash = UUID.randomUUID().toString();
- if (!crosspostService.createVKUser(vkID, loginhash, token.getAccessToken(), vkName, vkLink)) {
- logger.error("create vk user error");
- throw new HttpBadRequestException();
- }
- return "redirect:/signup?type=vk&hash=" + loginhash;
- }
- }
- /*
- @GetMapping("/_tglogin")
- public String doDurovLogin(HttpServletRequest request,
- @RequestParam Map<String, String> params,
- HttpServletResponse response) {
- String dataCheckString = params.entrySet().stream()
- .filter(p -> !p.getKey().equals("hash"))
- .sorted(Map.Entry.comparingByKey())
- .map(p -> p.getKey() + "=" + p.getValue())
- .collect(Collectors.joining("\n"));
- String hash = params.get("hash");
- byte[] secretKey = DigestUtils.sha256(telegramToken);
- String resultString = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(dataCheckString);
- if (hash.equals(resultString)) {
- Long tgUser = Long.valueOf(params.get("id"));
- int uid = telegramService.getUser(tgUser);
- if (uid > 0) {
- Cookie c = new Cookie("hash", userService.getHashByUID(uid));
- c.setMaxAge(50 * 24 * 60 * 60);
- response.addCookie(c);
- return Utils.getPreviousPageByRequest(request).orElse("redirect:/");
- } else {
- String username = StringUtils.defaultString(params.get("username"), params.get("first_name"));
- telegramService.createTelegramUser(tgUser, username);
- return "redirect:/signup?type=durov&hash=" + userService.getSignUpHashByTelegramID(tgUser, username);
- }
- } else {
- logger.warn("invalid tg hash {} for {}", resultString, hash);
- }
- throw new HttpBadRequestException();
- }*/
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Index.java b/juick-server/src/main/java/com/juick/server/api/Index.java
deleted file mode 100644
index 56f01370..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Index.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.Status;
-import com.juick.server.WebsocketManager;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import java.net.URI;
-
-/**
- * Created by vitalyster on 25.07.2016.
- */
-@RestController
-public class Index {
- @Inject
- private WebsocketManager wsHandler;
-
- @ApiIgnore
- @RequestMapping(value = { "/api/", "/ws/" }, method = RequestMethod.GET, headers = "Connection!=Upgrade")
- public ResponseEntity<Void> description() {
- URI redirectUri = ServletUriComponentsBuilder.fromCurrentRequestUri().path("/swagger-ui.html").build().toUri();
- return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).location(redirectUri).build();
- }
- @ApiIgnore
- @RequestMapping(value = "/api/status", method = RequestMethod.GET,
- produces = MediaType.APPLICATION_JSON_UTF8_VALUE, headers = "Connection!=Upgrade")
- public Status status() {
- return Status.getStatus(String.valueOf(wsHandler.getClients().size()));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Messages.java b/juick-server/src/main/java/com/juick/server/api/Messages.java
deleted file mode 100644
index 4f0009dd..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Messages.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.server.Utils;
-import com.juick.service.component.MessageReadEvent;
-import com.juick.model.CommandResult;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.TagService;
-import com.juick.service.UserService;
-import org.apache.commons.io.IOUtils;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.*;
-
-import javax.inject.Inject;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * @author ugnich
- */
-@RestController
-@RequestMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-public class Messages {
-
- private static final ResponseEntity<List<com.juick.Message>> NOT_FOUND = ResponseEntity
- .status(HttpStatus.NOT_FOUND)
- .body(Collections.emptyList());
-
- private static final ResponseEntity<List<com.juick.Message>> FORBIDDEN = ResponseEntity
- .status(HttpStatus.FORBIDDEN)
- .body(Collections.emptyList());
-
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- // TODO: serialize image urls
-
- @GetMapping("/api/home")
- public ResponseEntity<List<com.juick.Message>> getHome(
- @RequestParam(defaultValue = "0") int before_mid) {
- User visitor = UserUtils.getCurrentUser();
- if (!visitor.isAnonymous()) {
- int vuid = visitor.getUid();
- List<Integer> mids = messagesService.getMyFeed(vuid, before_mid, true);
- return ResponseEntity.ok(messagesService.getMessages(visitor, mids));
- }
- return FORBIDDEN;
- }
-
- @GetMapping("/api/messages")
- public ResponseEntity<List<com.juick.Message>> getMessages(
- @RequestParam(required = false) String uname,
- @RequestParam(name = "before_mid", defaultValue = "0") Integer before,
- @RequestParam(required = false, defaultValue = "0") Integer daysback,
- @RequestParam(required = false) String withrecommended,
- @RequestParam(required = false) String popular,
- @RequestParam(required = false) String search,
- @RequestParam(required = false, defaultValue = "0") Integer page,
- @RequestParam(required = false) String media,
- @RequestParam(required = false) String tag) {
-
- User visitor = UserUtils.getCurrentUser();
-
- List<Integer> mids;
- if (!StringUtils.isEmpty(uname)) {
- User user = userService.getUserByName(uname);
- if (!user.isAnonymous()) {
- if (!StringUtils.isEmpty(media)) {
- mids = messagesService.getUserPhotos(user.getUid(), 0, before);
- } else if (!StringUtils.isEmpty(tag)) {
- Tag tagObject = tagService.getTag(tag, false);
- if (tagObject != null) {
- mids = messagesService.getUserTag(user.getUid(), tagObject.TID, 0, before);
- } else {
- return NOT_FOUND;
- }
- } else if (!StringUtils.isEmpty(withrecommended)) {
- mids = messagesService.getUserBlogWithRecommendations(user.getUid(), 0, before);
- } else if (daysback > 0) {
- mids = messagesService.getUserBlogAtDay(user.getUid(), 0, daysback);
- } else if (!StringUtils.isEmpty(search)) {
- mids = messagesService.getUserSearch(visitor, user.getUid(), Utils.encodeSphinx(search), 0, page);
- } else {
- mids = messagesService.getUserBlog(user.getUid(), 0, before);
- }
- } else {
- return NOT_FOUND;
- }
- } else {
- if (!StringUtils.isEmpty(popular)) {
- mids = messagesService.getPopular(visitor.getUid(), before);
- } else if (!StringUtils.isEmpty(media)) {
- mids = messagesService.getPhotos(visitor.getUid(), before);
- } else if (!StringUtils.isEmpty(tag)) {
- Tag tagObject = tagService.getTag(tag, false);
- if (tagObject != null) {
- mids = messagesService.getTag(tagObject.TID, visitor.getUid(), before, 20);
- } else {
- return NOT_FOUND;
- }
- } else if (!StringUtils.isEmpty(search)) {
- mids = messagesService.getSearch(visitor, Utils.encodeSphinx(search), page);
- } else {
- mids = messagesService.getAll(visitor.getUid(), before);
- }
- }
- return ResponseEntity.ok(messagesService.getMessages(visitor, mids));
- }
- @DeleteMapping("/api/messages")
- public CommandResult deleteMessage(@RequestParam int mid, @RequestParam(required = false, defaultValue = "0") int rid) {
- User visitor = UserUtils.getCurrentUser();
- if (rid > 0) {
- if (messagesService.deleteReply(visitor.getUid(), mid, rid)) {
- return CommandResult.fromString("Reply deleted");
- }
- }
- if (messagesService.deleteMessage(visitor.getUid(), mid)) {
- return CommandResult.fromString("Message deleted");
- }
- throw new HttpBadRequestException();
- }
- @GetMapping("/api/messages/discussions")
- public List<Message> getDiscussions(
- @RequestParam(required = false, defaultValue = "0") Long to) {
- return messagesService.getMessages(UserUtils.getCurrentUser(), messagesService.getDiscussions(UserUtils.getCurrentUser().getUid(), to));
- }
- @GetMapping("/api/thread")
- public ResponseEntity<List<com.juick.Message>> getThread(
- @RequestParam(defaultValue = "0") int mid) {
- User visitor = UserUtils.getCurrentUser();
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- if (!messagesService.canViewThread(mid, visitor.getUid())) {
- return FORBIDDEN;
- } else {
- if (userService.getUserByName(msg.getUser().getName()).isBanned()) {
- throw new HttpNotFoundException();
- }
- msg.setRecommendations(new HashSet<>(messagesService.getMessageRecommendations(msg.getMid())));
- List<com.juick.Message> replies = messagesService.getReplies(visitor, mid);
- if (!visitor.isAnonymous()) {
- userService.updateLastSeen(visitor);
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, visitor, msg));
- }
- replies.add(0, msg);
- return ResponseEntity.ok(replies);
- }
- }
- return NOT_FOUND;
- }
- @GetMapping(value = "/api/thread/mark_read/{mid}-{rid}.gif", produces = MediaType.IMAGE_GIF_VALUE)
- public byte[] markThreadRead(@PathVariable int mid, @PathVariable int rid) throws IOException {
- User visitor = UserUtils.getCurrentUser();
- if (!visitor.isAnonymous()) {
- messagesService.setLastReadComment(visitor, mid, rid);
- Message msg = messagesService.getMessage(mid);
- userService.updateLastSeen(visitor);
- applicationEventPublisher.publishEvent(
- new MessageReadEvent(this, visitor, msg));
- return IOUtils.toByteArray(
- Objects.requireNonNull(getClass().getClassLoader().getResource("Transparent.gif")));
- }
- throw new HttpBadRequestException();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Notifications.java b/juick-server/src/main/java/com/juick/server/api/Notifications.java
deleted file mode 100644
index 62275f5a..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Notifications.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.Message;
-import com.juick.Status;
-import com.juick.ExternalToken;
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.service.MessagesService;
-import com.juick.service.PushQueriesService;
-import com.juick.service.SubscriptionService;
-import com.juick.server.util.UserUtils;
-import com.juick.service.UserService;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import java.io.IOException;
-import java.security.Principal;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Created by vitalyster on 24.10.2016.
- */
-@RestController
-public class Notifications {
-
- @Inject
- private PushQueriesService pushQueriesService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private SubscriptionService subscriptionService;
- @Inject
- private UserService userService;
-
-
- private User collectTokens(Integer uid) {
- User user = userService.getUserByUID(uid).orElse(AnonymousUser.INSTANCE);
- user.setUnreadCount(messagesService.getUnread(user).size());
- pushQueriesService.getGCMRegID(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "gcm", t, null)));
- pushQueriesService.getAPNSToken(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "apns", t, null)));
- pushQueriesService.getMPNSURL(uid).forEach(t -> user.getTokens().add(new ExternalToken(null, "mpns", t, null)));
- return user;
- }
-
- @ApiIgnore
- @RequestMapping(value = "/api/notifications", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public ResponseEntity<List<User>> doGet(
- @RequestParam(required = false, defaultValue = "0") int uid,
- @RequestParam(required = false, defaultValue = "0") int mid,
- @RequestParam(required = false, defaultValue = "0") int rid) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous() || !(visitor.getName().equals("juick"))) {
- throw new HttpForbiddenException();
- }
- if (uid > 0 && mid == 0) {
- // PM
- return ResponseEntity.ok(Collections.singletonList(collectTokens(uid)));
- } else {
- if (mid > 0) {
- // reply
- Message msg = messagesService.getMessage(mid);
- if (msg != null) {
- List<User> users;
- if (rid > 0) {
- Message op = messagesService.getMessage(mid);
- Message reply = messagesService.getReply(mid, rid);
- users = subscriptionService.getUsersSubscribedToComments(op, reply);
- } else {
- users = subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg);
- }
-
- return ResponseEntity.ok(users.stream().map(User::getUid)
- .map(this::collectTokens).collect(Collectors.toList()));
- }
- } else {
- // read
- return ResponseEntity.ok(Collections.singletonList(collectTokens(uid)));
- }
- }
- throw new HttpBadRequestException();
- }
-
- @ApiIgnore
- @RequestMapping(value = "/api/notifications", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doDelete(
- @RequestBody List<ExternalToken> list) {
- User visitor = UserUtils.getCurrentUser();
- if ((visitor.isAnonymous()) || !(visitor.getName().equals("juick"))) {
- throw new HttpForbiddenException();
- }
- list.forEach(t -> {
- switch (t.getType()) {
- case "gcm":
- pushQueriesService.deleteGCMToken(t.getToken());
- break;
- case "apns":
- pushQueriesService.deleteAPNSToken(t.getToken());
- break;
- case "mpns":
- pushQueriesService.deleteMPNSToken(t.getToken());
- break;
- default:
- throw new HttpBadRequestException();
- }
- });
-
- return Status.OK;
- }
- @ApiIgnore
- @RequestMapping(value = "/api/notifications/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doDeleteTokens(
- @RequestBody List<ExternalToken> list) {
- User visitor = UserUtils.getCurrentUser();
- if ((visitor.isAnonymous()) || !(visitor.getName().equals("juick"))) {
- throw new HttpForbiddenException();
- }
- list.forEach(t -> {
- switch (t.getType()) {
- case "gcm":
- pushQueriesService.deleteGCMToken(t.getToken());
- break;
- case "apns":
- pushQueriesService.deleteAPNSToken(t.getToken());
- break;
- case "mpns":
- pushQueriesService.deleteMPNSToken(t.getToken());
- break;
- default:
- throw new HttpBadRequestException();
- }
- });
-
- return Status.OK;
- }
-
- @ApiIgnore
- @RequestMapping(value = "/api/notifications", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doPut(
- @RequestBody List<ExternalToken> list) throws IOException {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- list.forEach(t -> {
- switch (t.getType()) {
- case "gcm":
- pushQueriesService.addGCMToken(visitor.getUid(), t.getToken());
- break;
- case "apns":
- pushQueriesService.addAPNSToken(visitor.getUid(), t.getToken());
- break;
- case "mpns":
- pushQueriesService.addMPNSToken(visitor.getUid(), t.getToken());
- break;
- default:
- throw new HttpBadRequestException();
- }
- });
- return Status.OK;
- }
-
- @Deprecated
- @RequestMapping(value = "/api/android/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doAndroidRegister(
- @RequestParam(name = "regid") String regId) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- pushQueriesService.addGCMToken(visitor.getUid(), regId);
- return Status.OK;
- }
-
- @Deprecated
- @RequestMapping(value = "/api/android/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doAndroidUnRegister(@RequestParam(name = "regid") String regId) {
- pushQueriesService.deleteGCMToken(regId);
- return Status.OK;
- }
-
- @Deprecated
- @RequestMapping(value = "/api/winphone/register", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doWinphoneRegister(
- Principal principal,
- @RequestParam(name = "url") String regId) {
- User visitor = UserUtils.getCurrentUser();
- pushQueriesService.addMPNSToken(visitor.getUid(), regId);
- return Status.OK;
- }
-
- @Deprecated
- @RequestMapping(value = "/api/winphone/unregister", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public Status doWinphoneUnRegister(@RequestParam(name = "url") String regId) {
- pushQueriesService.deleteMPNSToken(regId);
- return Status.OK;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/PM.java b/juick-server/src/main/java/com/juick/server/api/PM.java
deleted file mode 100644
index 0c36fe00..00000000
--- a/juick-server/src/main/java/com/juick/server/api/PM.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.Chat;
-import com.juick.User;
-import com.juick.service.component.MessageEvent;
-import com.juick.model.AnonymousUser;
-import com.juick.model.PrivateChats;
-import com.juick.server.util.*;
-import com.juick.service.PMQueriesService;
-import com.juick.service.UserService;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.inject.Inject;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * @author ugnich
- */
-@RestController
-public class PM {
- @Inject
- private UserService userService;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- @RequestMapping(value = "/api/pm", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public List<com.juick.Message> doGetPM(
- @RequestParam(required = false) String uname) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- int uid = 0;
- if (uname != null && uname.matches("^[a-zA-Z0-9\\-]{2,16}$")) {
- uid = userService.getUIDbyName(uname);
- }
-
- if (uid == 0) {
- throw new HttpBadRequestException();
- }
-
- return pmQueriesService.getPMMessages(visitor.getUid(), uid);
- }
-
- @RequestMapping(value = "/api/pm", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public com.juick.Message doPostPM(
- @RequestParam String uname,
- @RequestParam String body) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- User userTo = AnonymousUser.INSTANCE;
- if (WebUtils.isUserName(uname)) {
- userTo = userService.getUserByName(uname);
- }
-
- if (userTo.getUid() == 0 || body == null || body.length() < 1 || body.length() > 10240) {
- throw new HttpBadRequestException();
- }
-
- if (userService.isInBLAny(userTo.getUid(), visitor.getUid())) {
- throw new HttpForbiddenException();
- }
-
- if (pmQueriesService.createPM(visitor.getUid(), userTo.getUid(), body)) {
- com.juick.Message jmsg = new com.juick.Message();
- jmsg.setUser(visitor);
- jmsg.setText(body);
- jmsg.setTo(userTo);
- applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg, Collections.singletonList(jmsg.getTo())));
- return jmsg;
-
- }
- throw new HttpBadRequestException();
- }
- @RequestMapping(value = "/api/groups_pms", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public PrivateChats doGetGroupsPMs(
- @RequestParam(defaultValue = "5") int cnt) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- // TODO: ignore cnt param for now but make sure paging param will not be cnt
-
- List<Chat> lastconv = pmQueriesService.getLastChats(visitor);
- PrivateChats pms = new PrivateChats();
- pms.setUsers(lastconv);
- return pms;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Post.java b/juick-server/src/main/java/com/juick/server/api/Post.java
deleted file mode 100644
index 303ff109..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Post.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.Message;
-import com.juick.Reaction;
-import com.juick.Status;
-import com.juick.User;
-import com.juick.server.CommandsManager;
-import com.juick.model.CommandResult;
-import com.juick.server.util.*;
-import com.juick.service.MessagesService;
-import com.juick.service.SubscriptionService;
-import com.juick.service.UserService;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.inject.Inject;
-import javax.validation.constraints.NotNull;
-import java.net.URI;
-import java.net.URL;
-import java.util.List;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@RestController
-public class Post {
- private static Logger logger = LoggerFactory.getLogger(Post.class);
-
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private SubscriptionService subscriptionService;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
- @Inject
- CommandsManager commandsManager;
-
- @RequestMapping(value = "/api/post", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- @ResponseStatus(value = HttpStatus.OK)
- public CommandResult doPostMessage(
- @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body,
- @RequestParam(required = false) String img,
- @RequestParam(required = false) MultipartFile attach) throws Exception {
- User visitor = UserUtils.getCurrentUser();
-
- if (visitor.isAnonymous())
- throw new HttpForbiddenException();
-
- if (body.length() > 4096) {
- throw new HttpBadRequestException();
- }
- body = body.replace("\r", StringUtils.EMPTY);
-
- URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, tmpDir);
-
- if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) {
- URI juickUri = URI.create(img);
- if (juickUri.getScheme().equals("juick")) {
- attachmentFName = juickUri;
- } else {
- try {
- URL imgUrl = new URL(img);
- attachmentFName = HttpUtils.downloadImage(imgUrl, tmpDir);
- } catch (Exception e) {
- logger.error("DOWNLOAD ERROR", e);
- throw new HttpBadRequestException();
- }
- }
- }
- if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) {
- // Should be there for compatibility
- throw new HttpBadRequestException();
- }
- return commandsManager.processCommand(visitor, body, attachmentFName);
- }
-
- @RequestMapping(value = "/api/comment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public CommandResult doPostComment(
- @RequestParam(defaultValue = "0") int mid,
- @RequestParam(defaultValue = "0") int rid,
- @RequestParam(required = false, defaultValue = StringUtils.EMPTY) String body,
- @RequestParam(required = false) String img,
- @RequestParam(required = false) MultipartFile attach)
- throws Exception {
- User visitor = UserUtils.getCurrentUser();
- int vuid = visitor.getUid();
- if (vuid == 0) {
- throw new HttpForbiddenException();
- }
- if (mid == 0) {
- throw new HttpBadRequestException();
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg == null) {
- throw new HttpNotFoundException();
- }
-
- com.juick.Message reply = null;
- if (rid > 0) {
- reply = messagesService.getReply(mid, rid);
- if (reply == null) {
- throw new HttpNotFoundException();
- }
- }
-
- if (body.length() > 4096) {
- throw new HttpBadRequestException();
- }
- body = body.replace("\r", StringUtils.EMPTY);
-
- if ((msg.ReadOnly && msg.getUser().getUid() != vuid) || userService.isInBLAny(msg.getUser().getUid(), vuid)
- || (reply != null && userService.isInBLAny(reply.getUser().getUid(), vuid))) {
- throw new HttpForbiddenException();
- }
-
- URI attachmentFName = HttpUtils.receiveMultiPartFile(attach, tmpDir);
-
- if (StringUtils.isBlank(attachmentFName.toString()) && img != null && img.length() > 10) {
- try {
- attachmentFName = HttpUtils.downloadImage(new URL(img), tmpDir);
- } catch (Exception e) {
- logger.error("DOWNLOAD ERROR", e);
- throw new HttpBadRequestException();
- }
- }
- if (StringUtils.isBlank(body) && StringUtils.isBlank(attachmentFName.toString())) {
- // Should be there for compatibility
- throw new HttpBadRequestException();
- }
- return commandsManager.processCommand(visitor, String.format("#%d/%d %s", mid, rid, body),
- attachmentFName);
- }
-
- @PostMapping("/api/like")
- @ResponseStatus(value = HttpStatus.OK)
- public Status doPostRecomm(@RequestParam Integer mid) throws Exception {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg == null) {
- throw new HttpNotFoundException();
- }
- if (msg.getUser().getUid() == visitor.getUid()) {
- throw new HttpForbiddenException();
- }
- CommandResult status = commandsManager.processCommand(visitor, String.format("! #%d", mid),
- URI.create(StringUtils.EMPTY));
- return Status.getStatus(status.getText());
- }
-
- @PostMapping("/api/subscribe")
- @ResponseStatus(value = HttpStatus.OK)
- public Status doPostSubscribe(@RequestParam Integer mid) throws Exception {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg == null) {
- throw new HttpNotFoundException();
- }
- if (msg.getUser().getUid() == visitor.getUid()) {
- throw new HttpForbiddenException();
- }
- CommandResult status = commandsManager.processCommand(visitor, String.format("S #%d", mid),
- URI.create(StringUtils.EMPTY));
- return Status.getStatus(status.getText());
- }
-
- @GetMapping("/api/reactions")
- @ResponseStatus(value = HttpStatus.OK)
- public List<Reaction> reactionsList() {
- return messagesService.listReactions();
- }
-
- @PostMapping("/api/react")
- @ResponseStatus(value = HttpStatus.OK)
- public Status doPostReact(@RequestParam Integer mid,@RequestParam @NotNull int reactionId,
- @RequestParam (required = false, defaultValue = "1") int count) {
-
- logger.info("got reaction with type: {}", reactionId);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- com.juick.Message msg = messagesService.getMessage(mid);
- if (msg == null) {
- throw new HttpNotFoundException();
- }
- if (msg.getUser().getUid() == visitor.getUid()) {
- throw new HttpForbiddenException();
- }
- MessagesService.RecommendStatus recommendStatus = MessagesService.RecommendStatus.Error;
- for (int i = 0; i < count; i++)
- recommendStatus = messagesService.likeMessage(mid, visitor.getUid(),
- reactionId);
-
- return recommendStatus == MessagesService.RecommendStatus.Error ? Status.ERROR :Status.OK;
- }
-
- @PostMapping("/api/update")
- public CommandResult updateMessage(@RequestParam Integer mid,
- @RequestParam(required = false, defaultValue = "0") Integer rid,
- @RequestParam String body) {
- User visitor = UserUtils.getCurrentUser();
- User author = rid == 0 ? messagesService.getMessageAuthor(mid) : messagesService.getReply(mid, rid).getUser();
- if (visitor.equals(author)) {
- if (messagesService.updateMessage(mid, rid, body)) {
- Message result = rid == 0 ? messagesService.getMessage(mid) : messagesService.getReply(mid, rid);
- return CommandResult.build(result, "Message updated", StringUtils.EMPTY);
- }
- throw new HttpBadRequestException();
- }
- throw new HttpForbiddenException();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Service.java b/juick-server/src/main/java/com/juick/server/api/Service.java
deleted file mode 100644
index ed62886f..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Service.java
+++ /dev/null
@@ -1,166 +0,0 @@
-package com.juick.server.api;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.server.CommandsManager;
-import com.juick.server.EmailManager;
-import com.juick.server.ServerManager;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.EmailService;
-import com.juick.service.UserService;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.mail.util.MimeMessageParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import javax.mail.Session;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Paths;
-import java.util.*;
-
-@Controller
-public class Service {
- private static Logger logger = LoggerFactory.getLogger(Service.class);
- @Inject
- private UserService userService;
- @Inject
- private EmailService emailService;
- @Inject
- private CommandsManager commandsManager;
- @Inject
- private EmailManager emailManager;
- @Value("${api_user:juick}")
- private String serviceUser;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${banned_emails:}")
- private String[] ignoredEmails;
- @Inject
- private ServerManager serverManager;
-
- private Session session = Session.getDefaultInstance(new Properties());
-
- @ApiIgnore
- @PostMapping("/api/mail")
- @ResponseStatus(value = HttpStatus.OK)
- public void processMail(InputStream data) throws Exception {
- if (UserUtils.getCurrentUser().getName().equals(serviceUser)) {
- MimeMessage msg = new MimeMessage(session, data);
- String[] returnPaths = msg.getHeader("Return-Path");
- if (returnPaths != null) {
- logger.info("got msg with return path {}", returnPaths[0]);
- if (returnPaths[0].equals("<>")) {
- return;
- }
- }
- String from = msg.getFrom() == null || msg.getFrom().length > 1 ? ((InternetAddress) msg.getSender()).getAddress()
- : ((InternetAddress) msg.getFrom()[0]).getAddress();
-
- User visitor = userService.getUserByEmail(from);
- if (!visitor.isAnonymous()) {
- MimeMessageParser parser = new MimeMessageParser(msg);
- parser.parse();
- final String[] body = {parser.getPlainContent()};
- if (body[0] == null) {
- parser.getAttachmentList().stream()
- .filter(a -> a.getContentType().equals("text/plain")).findFirst()
- .ifPresent(a -> {
- try {
- body[0] = IOUtils.toString(a.getInputStream(), StandardCharsets.UTF_8);
- logger.info("got text: {}", body[0]);
- } catch (IOException e) {
- logger.info("attachment error: {}", e);
- }
- });
- }
- final String[] attachmentFName = new String[1];
- parser.getAttachmentList().stream().filter(a ->
- a.getContentType().equals("image/jpeg") || a.getContentType().equals("image/png"))
- .findFirst().ifPresent(a -> {
- logger.info("got attachment: {}", a.getContentType());
- String attachmentType;
- if (a.getContentType().equals("image/jpeg")) {
- attachmentType = "jpg";
- } else {
- attachmentType = "png";
- }
- attachmentFName[0] = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType;
- try {
- logger.info("got inputstream: {}", a.getInputStream());
- FileOutputStream fos = new FileOutputStream(Paths.get(tmpDir, attachmentFName[0]).toString());
- IOUtils.copy(a.getInputStream(), fos);
- fos.close();
- } catch (IOException e) {
- logger.info("attachment error: {}", e);
- }
- });
- String[] inReplyToHeaders = msg.getHeader("In-Reply-To");
- if (inReplyToHeaders != null && inReplyToHeaders.length > 0) {
- Scanner inReplyToScanner = new Scanner(inReplyToHeaders[0].trim()).useDelimiter(EmailManager.MSGID_PATTERN);
- int mid = Integer.parseInt(inReplyToScanner.next());
- int rid = Integer.parseInt(inReplyToScanner.next());
- logger.info("Message is reply to #{}/{}", mid, rid);
- body[0] = rid > 0 ? String.format("#%d/%d %s", mid, rid, body[0])
- : String.format("#%d %s", mid, body[0]);
- }
- URI attachmentUri = StringUtils.isNotEmpty(attachmentFName[0]) ? URI.create(String.format("juick://%s", attachmentFName[0]))
- : URI.create(StringUtils.EMPTY);
- commandsManager.processCommand(visitor, body[0], attachmentUri);
- } else {
- if (!Arrays.asList(ignoredEmails).contains(from)) {
- String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
- emailService.addVerificationCode(null, from, verificationCode);
- String signupUrl = String.format("Follow this link to create Juick account: https://juick.com/signup?type=email&hash=%s", verificationCode);
- emailManager.sendEmail(from, "Juick registration", signupUrl, StringUtils.EMPTY, Collections.emptyMap());
- }
- }
- } else {
- throw new HttpForbiddenException();
- }
- }
- private void endSession(SseEmitter emitter) {
- serverManager.getSessions().stream()
- .filter(s -> s.getEmitter().equals(emitter))
- .forEach(session -> serverManager.getSessions().remove(session));
- }
- @GetMapping("/api/events")
- public SseEmitter handle() throws IOException {
- User visitor = UserUtils.getCurrentUser();
- logger.info("{} connected", visitor.getName());
- if (!visitor.isAnonymous()) {
- userService.updateLastSeen(visitor);
- }
- SseEmitter emitter = new SseEmitter(600000L);
- serverManager.getSessions().add(new ServerManager.EventSession(visitor, emitter));
-
- emitter.onCompletion(() -> endSession(emitter));
- emitter.onTimeout(() -> endSession(emitter));
-
- return emitter;
- }
- @ExceptionHandler(AsyncRequestTimeoutException.class)
- public void eventErrorHandler(Exception ex) {
- logger.debug("SSE timeout", ex);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Tags.java b/juick-server/src/main/java/com/juick/server/api/Tags.java
deleted file mode 100644
index 7a8e572a..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Tags.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.User;
-import com.juick.model.TagStats;
-import com.juick.server.util.UserUtils;
-import com.juick.service.TagService;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.inject.Inject;
-import java.util.List;
-
-/**
- * Created by vitalyster on 29.11.2016.
- */
-@RestController
-public class Tags {
- @Inject
- private TagService tagService;
-
- @RequestMapping(value = "/api/tags", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public List<TagStats> tags(
- @RequestParam(required = false, defaultValue = "0") int user_id
- ) {
- User visitor = UserUtils.getCurrentUser();
- if (user_id == 0) {
- user_id = visitor.getUid();
- }
- if (user_id > 0) {
- return tagService.getUserTagStats(user_id);
- }
- return tagService.getTagStats();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/Users.java b/juick-server/src/main/java/com/juick/server/api/Users.java
deleted file mode 100644
index 7686d722..00000000
--- a/juick-server/src/main/java/com/juick/server/api/Users.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api;
-
-import com.juick.User;
-import com.juick.model.ApplicationStatus;
-import com.juick.model.UserInfo;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.service.CrosspostService;
-import com.juick.service.EmailService;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import com.juick.server.util.UserUtils;
-import com.juick.server.util.WebUtils;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-
-import javax.inject.Inject;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * @author ugnich
- */
-@RestController
-public class Users {
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private EmailService emailService;
-
- @RequestMapping(value = "/api/auth", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public String getAuthToken() {
- return userService.getHashByUID(UserUtils.getCurrentUser().getUid());
- }
-
- @RequestMapping(value = "/api/users", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public List<User> doGetUsers(
- @RequestParam(value = "uname", required = false) List<String> unames) {
- List<com.juick.User> users = new ArrayList<>();
-
- if (unames != null) {
- unames.removeIf(WebUtils::isNotUserName);
-
- if (!unames.isEmpty() && unames.size() < 20)
- users.addAll(userService.getUsersByName(unames));
- }
-
- if (!users.isEmpty())
- return users;
- if (!UserUtils.getCurrentUser().isAnonymous()) {
- return Collections.singletonList(UserUtils.getCurrentUser());
- }
-
- throw new HttpNotFoundException();
- }
-
- @GetMapping("/api/me")
- public SecureUser getMe() {
- User visitor = UserUtils.getCurrentUser();
- SecureUser me = new SecureUser();
- me.setUid(visitor.getUid());
- me.setName(visitor.getName());
- me.setAuthHash(getAuthToken());
- List<Integer> unread = messagesService.getUnread(visitor);
- me.setUnread(unread);
- me.setUnreadCount(unread.size());
- me.setRead(userService.getUserFriends(visitor.getUid()));
- me.setReaders(userService.getUserReaders(visitor.getUid()));
- return me;
- }
-
- @RequestMapping(value = "/api/users/read", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public List<User> doGetUserRead(
- @RequestParam String uname) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- int uid = 0;
- if (uname == null) {
- uid = visitor.getUid();
- } else {
- if (WebUtils.isUserName(uname)) {
- com.juick.User u = userService.getUserByName(uname);
- if (!u.isAnonymous()) {
- uid = u.getUid();
- }
- }
- }
-
- if (uid > 0) {
- return userService.getUserFriends(uid);
- }
- throw new HttpNotFoundException();
- }
-
- @RequestMapping(value = "/api/users/readers", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public List<User> doGetUserReaders(
- @RequestParam String uname) {
- User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpForbiddenException();
- }
- int uid = 0;
- if (uname == null) {
- uid = visitor.getUid();
- } else {
- if (WebUtils.isUserName(uname)) {
- com.juick.User u = userService.getUserByName(uname);
- if (!u.isAnonymous()) {
- uid = u.getUid();
- }
- }
- }
-
- if (uid > 0) {
- return userService.getUserReaders(uid);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping("/api/info/{uname}")
- public UserInfo getUserInfo(@PathVariable String uname) {
- User user = userService.getUserByName(uname);
- if (!user.isBanned()) {
- return userService.getUserInfo(user);
- }
- throw new HttpNotFoundException();
- }
-
- class SecureUser extends User {
- public String getHash() {
- return getAuthHash();
- }
- public UserInfo getUserInfo() {
- return userService.getUserInfo(this);
- }
- public List<String> getJIDs() {
- return userService.getAllJIDs(this);
- }
- public List<String> getEmails() {
- return userService.getEmails(this);
- }
- public String getActiveEmail() {
- return emailService.getNotificationsEmail(this.getUid());
- }
- public String getTwitterName() {
- return crosspostService.getTwitterName(this.getUid());
- }
- public String getTelegramName() {
- return crosspostService.getTelegramName(this.getUid());
- }
- public ApplicationStatus getFacebookStatus() {
- return crosspostService.getFbCrossPostStatus(this.getUid());
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java b/juick-server/src/main/java/com/juick/server/api/activity/Profile.java
deleted file mode 100644
index 10390ea1..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/Profile.java
+++ /dev/null
@@ -1,379 +0,0 @@
-package com.juick.server.api.activity;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.juick.Message;
-import com.juick.User;
-import com.juick.model.CommandResult;
-import com.juick.server.ActivityPubManager;
-import com.juick.server.CommandsManager;
-import com.juick.server.KeystoreManager;
-import com.juick.server.SignatureManager;
-import com.juick.server.api.activity.model.Activity;
-import com.juick.server.api.activity.model.Context;
-import com.juick.server.api.activity.model.activities.Announce;
-import com.juick.server.api.activity.model.activities.Create;
-import com.juick.server.api.activity.model.activities.Delete;
-import com.juick.server.api.activity.model.activities.Follow;
-import com.juick.server.api.activity.model.activities.Undo;
-import com.juick.server.api.activity.model.objects.Image;
-import com.juick.server.api.activity.model.objects.Key;
-import com.juick.server.api.activity.model.objects.Note;
-import com.juick.server.api.activity.model.objects.OrderedCollection;
-import com.juick.server.api.activity.model.objects.OrderedCollectionPage;
-import com.juick.server.api.activity.model.objects.Person;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import com.juick.service.activities.DeleteUserEvent;
-import com.juick.service.activities.FollowEvent;
-import com.juick.service.activities.UndoFollowEvent;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.inject.Inject;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-@RestController
-public class Profile {
- private static final Logger logger = LoggerFactory.getLogger(Profile.class);
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private KeystoreManager keystoreManager;
- @Inject
- private SignatureManager signatureManager;
- @Inject
- private ActivityPubManager activityPubManager;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Inject
- private CommandsManager commandsManager;
- @Value("${web_domain:localhost}")
- private String domain;
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- @Value("${img_url:http://localhost:8080/i/}")
- private String baseImagesUri;
- @Inject
- private ObjectMapper jsonMapper;
-
- @GetMapping(value = "/u/{userName}", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public Person getUser(@PathVariable String userName) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- Person person = new Person();
- person.setId(activityPubManager.personUri(user));
- person.setUrl(activityPubManager.personWebUri(user));
- person.setName(userName);
- person.setPreferredUsername(userName);
- Key publicKey = new Key();
- publicKey.setId(person.getId() + "#main-key");
- publicKey.setOwner(person.getId());
- publicKey.setPublicKeyPem(keystoreManager.getPublicKeyPem());
- person.setPublicKey(publicKey);
- person.setInbox(activityPubManager.inboxUri());
- person.setOutbox(activityPubManager.outboxUri(user));
- person.setFollowers(activityPubManager.followersUri(user));
- person.setFollowing(activityPubManager.followingUri(user));
- UriComponentsBuilder image = UriComponentsBuilder.fromUriString(baseImagesUri);
- image.path(String.format("/a/%d.png", user.getUid()));
- Image avatar = new Image();
- avatar.setUrl(image.toUriString());
- avatar.setMediaType("image/png");
- person.setIcon(avatar);
- return (Person) Context.build(person);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/blog/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollection getOutbox(@PathVariable String userName) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
- OrderedCollection blog = new OrderedCollection();
- blog.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- blog.setTotalItems(userService.getStatsMessages(user.getUid()));
- blog.setFirst(uriComponentsBuilder.path(String.format("/u/%s/blog", userName)).toUriString());
- return (OrderedCollection) Context.build(blog);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/blog", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollectionPage getOutboxPage(@PathVariable String userName,
- @RequestParam(required = false, defaultValue = "0") int before) {
- User visitor = UserUtils.getCurrentUser();
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uri = UriComponentsBuilder.fromUriString(baseUri);
- String personUri = uri.path(String.format("/u/%s", userName)).toUriString();
- List<Integer> mids = messagesService.getUserBlog(user.getUid(), 0, before);
- List<Note> notes = messagesService.getMessages(visitor, mids).stream().map(activityPubManager::makeNote).collect(Collectors.toList());
- OrderedCollectionPage page = new OrderedCollectionPage();
- page.setPartOf(uri.replacePath(String.format("/u/%s/blog/toc", userName)).toUriString());
- page.setFirst(uri.replacePath(String.format("/u/%s/blog", userName)).toUriString());
- page.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- page.setOrderedItems(notes.stream().map(a -> {
- Create create = new Create();
- create.setId(a.getId() + "#Create");
- create.setTo(a.getTo());
- create.setActor(personUri);
- create.setObject(a);
- create.setPublished(a.getPublished());
- return create;
- }).collect(Collectors.toList()));
- int beforeNext = mids.stream().reduce((fst, second) -> second).orElse(0);
- if (beforeNext > 0) {
- page.setNext(uri.queryParam("before", beforeNext).toUriString());
- }
- page.setLast(uri.replaceQueryParam("before", "1").toUriString());
- return (OrderedCollectionPage) Context.build(page);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/followers/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollection getFollowers(@PathVariable String userName) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
- OrderedCollection followers = new OrderedCollection();
- followers.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- followers.setTotalItems(userService.getStatsMyReaders(user.getUid()));
- followers.setFirst(uriComponentsBuilder.path(String.format("/u/%s/followers", userName)).toUriString());
- return (OrderedCollection) Context.build(followers);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/followers", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollectionPage getFollowersPage(@PathVariable String userName,
- @RequestParam(required = false, defaultValue = "0") int page) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
- uriComponentsBuilder.path(String.format("/u/%s/followers", userName));
- List<User> followers = userService.getUserReaders(user.getUid());
- Stream<User> followersPage = followers.stream().skip(20 * page).limit(20);
-
- OrderedCollectionPage result = new OrderedCollectionPage();
- result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- result.setOrderedItems(followersPage.map(a -> {
- Person follower = new Person();
- follower.setName(a.getName());
- follower.setPreferredUsername(a.getName());
- follower.setUrl(activityPubManager.personWebUri(a));
- return follower;
- }).collect(Collectors.toList()));
- boolean hasNext = followers.size() <= 20 * page;
- if (hasNext) {
- result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString());
- }
- return (OrderedCollectionPage) Context.build(result);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/following/toc", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollection getFollowing(@PathVariable String userName) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
- OrderedCollection following = new OrderedCollection();
- following.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- following.setTotalItems(userService.getUserFriends(user.getUid()).size());
- following.setFirst(uriComponentsBuilder.path(String.format("/u/%s/followers", userName)).toUriString());
- return (OrderedCollection) Context.build(following);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/u/{userName}/following", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public OrderedCollectionPage getFollowingPage(@PathVariable String userName,
- @RequestParam(required = false, defaultValue = "0") int page) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUri);
- uriComponentsBuilder.path(String.format("/u/%s/following", userName));
- List<User> following = userService.getUserFriends(user.getUid());
- Stream<User> followingPage = following.stream().skip(20 * page).limit(20);
-
- OrderedCollectionPage result = new OrderedCollectionPage();
- result.setId(ServletUriComponentsBuilder.fromCurrentRequestUri().toUriString());
- result.setOrderedItems(followingPage.map(a -> {
- Person follower = new Person();
- follower.setName(a.getName());
- follower.setPreferredUsername(a.getName());
- follower.setUrl(activityPubManager.personWebUri(a));
- return follower;
- }).collect(Collectors.toList()));
- boolean hasNext = following.size() <= 20 * page;
- if (hasNext) {
- result.setNext(uriComponentsBuilder.queryParam("page", page + 1).toUriString());
- }
- return (OrderedCollectionPage) Context.build(result);
- }
- throw new HttpNotFoundException();
- }
-
- @GetMapping(value = "/n/{mid}-{rid}", produces = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public Context showNote(@PathVariable int mid, @PathVariable int rid) {
- if (rid > 0) {
- // reply
- return Context.build(activityPubManager.makeNote(
- messagesService.getReply(mid, rid)));
- }
- return Context.build(activityPubManager.makeNote(
- messagesService.getMessage(mid)));
- }
-
- @PostMapping(value = "/api/inbox", consumes = {Context.LD_JSON_MEDIA_TYPE, Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE})
- public ResponseEntity<Void> processInbox(@RequestBody Activity activity,
- @RequestHeader(name = "Host") String host,
- @RequestHeader(name = "Date") String date,
- @RequestHeader(name = "Digest", required = false) String digest,
- @RequestHeader(name = "Content-Type") String contentType,
- @RequestHeader(name = "User-Agent", required = false) String userAgent,
- @RequestHeader(name = "Accept-Encoding", required = false) String acceptEncoding,
- @RequestHeader(name = "Signature", required = false) String signature) throws Exception {
- UriComponents componentsBuilder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- Map<String, String> headers = new HashMap<>();
- headers.put("host", host.split(":", 2)[0]);
- headers.put("date", date);
- headers.put("digest", digest);
- headers.put("content-type", contentType);
- headers.put("user-agent", userAgent);
- headers.put("accept-encoding", acceptEncoding);
- boolean valid = signatureManager.verifySignature(signature, URI.create(activity.getActor()), "POST",
- componentsBuilder.getPath(), headers);
- if (valid) {
- if (activity instanceof Follow) {
- Follow followRequest = (Follow) activity;
- String actor = followRequest.getActor();
- Person follower = (Person) signatureManager.getContext(URI.create(actor)).orElseThrow(HttpBadRequestException::new);
- applicationEventPublisher.publishEvent(
- new FollowEvent(this, followRequest));
- return new ResponseEntity<>(HttpStatus.ACCEPTED);
-
- }
- if (activity instanceof Undo) {
- String follower = (String) ((Map) activity.getObject()).get("object");
- applicationEventPublisher.publishEvent(new UndoFollowEvent(this, activity.getActor(), follower));
- return new ResponseEntity<>(HttpStatus.OK);
- }
- if (activity instanceof Delete) {
- if (activity.getObject() instanceof String) {
- // Delete user
- applicationEventPublisher.publishEvent(new DeleteUserEvent(this, (String)activity.getObject()));
- return new ResponseEntity<>(HttpStatus.OK);
- }
- }
- if (activity instanceof Create) {
- if (activity.getObject() instanceof Map) {
- Map<String, Object> note = (Map<String, Object>) activity.getObject();
- if (note.get("type").equals("Note")) {
- URI noteId = URI.create((String) note.get("id"));
- if (messagesService.replyExists(noteId)) {
- return new ResponseEntity<>(HttpStatus.OK);
- } else {
- String inReplyTo = (String) note.get("inReplyTo");
- if (StringUtils.isNotBlank(inReplyTo)) {
- if (inReplyTo.startsWith(baseUri)) {
- UriComponents uri = UriComponentsBuilder.fromUriString(inReplyTo).build();
- String postId = uri.getPath().substring(uri.getPath().lastIndexOf('/') + 1).replace("-", "/");
- User user = new User();
- user.setUri(URI.create(activity.getActor()));
- String attachment = StringUtils.EMPTY;
- if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) {
- Map<String, Object> attachmentObj = (Map<String, Object>) ((List<Object>) note.get("attachment")).get(0);
- attachment = (String) attachmentObj.get("url");
- }
- CommandResult result = commandsManager.processCommand(user, String.format("#%s %s", postId, note.get("content")), URI.create(attachment));
- logger.info(jsonMapper.writeValueAsString(result));
- if (result.getNewMessage().isPresent()) {
- messagesService.updateReplyUri(result.getNewMessage().get(), noteId);
- return new ResponseEntity<>(HttpStatus.OK);
- } else {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
- }
- } else {
- Message reply = messagesService.getReplyByUri(inReplyTo);
- if (reply != null) {
- User user = new User();
- user.setUri(URI.create(activity.getActor()));
- String attachment = StringUtils.EMPTY;
- if (note.get("attachment") != null && ((List) note.get("attachment")).size() > 0) {
- Map<String, Object> attachmentObj = (Map<String, Object>) ((List<Object>) note.get("attachment")).get(0);
- attachment = (String) attachmentObj.get("url");
- }
- CommandResult result = commandsManager.processCommand(user, String.format("#%d/%d %s", reply.getMid(), reply.getRid(), note.get("content")), URI.create(attachment));
- logger.info(jsonMapper.writeValueAsString(result));
- if (result.getNewMessage().isPresent()) {
- messagesService.updateReplyUri(result.getNewMessage().get(), noteId);
- return new ResponseEntity<>(HttpStatus.OK);
- } else {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
- }
- }
- }
- }
- }
- }
- }
- }
- if (activity instanceof Delete) {
- Map<String, Object> tombstone = (Map<String, Object>) activity.getObject();
- if (tombstone.get("type").equals("Tombstone")) {
- URI actor = URI.create(activity.getActor());
- URI reply = URI.create((String)tombstone.get("id"));
- messagesService.deleteReply(actor, reply);
- return new ResponseEntity<>(HttpStatus.OK);
- }
- }
- if (activity instanceof Announce) {
- logger.info("Announce: {}", jsonMapper.writeValueAsString(activity));
- return new ResponseEntity<>(HttpStatus.OK);
- }
- logger.warn("Unknown activity: {}", jsonMapper.writeValueAsString(activity));
- return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
- }
- return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
- }
- @PostMapping(value = "/u/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public User fetchUser(@RequestParam URI uri) {
- Person person = (Person) signatureManager.getContext(uri).orElseThrow(HttpBadRequestException::new);
- User user = new User();
- user.setUri(URI.create(person.getUrl()));
- user.setName(person.getPreferredUsername());
- if (person.getIcon() != null) {
- user.setAvatar(person.getIcon().getUrl());
- }
- return user;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/Activity.java b/juick-server/src/main/java/com/juick/server/api/activity/model/Activity.java
deleted file mode 100644
index ec126b88..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/Activity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.juick.server.api.activity.model;
-
-public abstract class Activity extends Context {
-
- private String actor;
- private Object object;
-
- public String getActor() {
- return actor;
- }
-
- public void setActor(String actor) {
- this.actor = actor;
- }
-
- public Object getObject() {
- return object;
- }
-
- public void setObject(Object object) {
- this.object = object;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/Context.java b/juick-server/src/main/java/com/juick/server/api/activity/model/Context.java
deleted file mode 100644
index 0df8f8c7..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/Context.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package com.juick.server.api.activity.model;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.juick.server.api.activity.model.activities.*;
-import com.juick.server.api.activity.model.objects.*;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property="type")
-@JsonSubTypes({
- @JsonSubTypes.Type(value = Create.class, name = "Create"),
- @JsonSubTypes.Type(value = Delete.class, name = "Delete"),
- @JsonSubTypes.Type(value = Follow.class, name = "Follow"),
- @JsonSubTypes.Type(value = Accept.class, name = "Accept"),
- @JsonSubTypes.Type(value = Undo.class, name = "Undo"),
- @JsonSubTypes.Type(value = Like.class, name = "Like"),
- @JsonSubTypes.Type(value = Block.class, name = "Block"),
- @JsonSubTypes.Type(value = Announce.class, name = "Announce"),
- @JsonSubTypes.Type(value = Activity.class, name = "Activity"),
- @JsonSubTypes.Type(value = Image.class, name = "Image"),
- @JsonSubTypes.Type(value = Key.class, name = "Key"),
- @JsonSubTypes.Type(value = Link.class, name = "Link"),
- @JsonSubTypes.Type(value = Hashtag.class, name = "Hashtag"),
- @JsonSubTypes.Type(value = Mention.class, name = "Mention"),
- @JsonSubTypes.Type(value = Note.class, name = "Note"),
- @JsonSubTypes.Type(value = OrderedCollection.class, name = "OrderedCollection"),
- @JsonSubTypes.Type(value = OrderedCollectionPage.class, name = "OrderedCollectionPage"),
- @JsonSubTypes.Type(value = Person.class, name = "Person")
-})
-public abstract class Context {
-
- private List<Object> context;
-
- private String id;
-
- private String name;
-
- private Instant published;
-
- private String url;
-
- private List<String> to;
-
- private List<Context> tags;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getType() {
- return getClass().getSimpleName();
- }
-
- @JsonProperty("@context")
- public List<Object> getContext() {
- return context;
- }
-
- public final static String ACTIVITY_STREAMS_URI = "https://www.w3.org/ns/activitystreams";
- public final static String SECURITY_URI = "https://w3id.org/security/v1";
- public final static String LD_JSON_MEDIA_TYPE = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"";
- public final static String ACTIVITY_MEDIA_TYPE = "application/activity+json";
- public final static String ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE = ACTIVITY_MEDIA_TYPE + "; profile=\"https://www.w3.org/ns/activitystreams\"";
-
- public Instant getPublished() {
- return published;
- }
-
- public void setPublished(Instant published) {
- this.published = published;
- }
-
- public List<String> getTo() {
- return to;
- }
-
- public void setTo(List<String> to) {
- this.to = to;
- }
-
- public static Context build(Context response) {
- response.context = new ArrayList(Arrays.asList(ACTIVITY_STREAMS_URI, SECURITY_URI));
- response.context.add(Collections.singletonMap("Hashtag", "as:Hashtag"));
- return response;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- @JsonProperty("tag")
- public List<Context> getTags() {
- return tags;
- }
-
- public void setTags(List<Context> tags) {
- this.tags = tags;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Accept.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Accept.java
deleted file mode 100644
index 1e0a9968..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Accept.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Accept extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Announce.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Announce.java
deleted file mode 100644
index f2859404..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Announce.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Announce extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Block.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Block.java
deleted file mode 100644
index 0e5a02d4..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Block.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Block extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Create.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Create.java
deleted file mode 100644
index 52507373..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Create.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Create extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Delete.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Delete.java
deleted file mode 100644
index f4392020..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Delete.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Delete extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Follow.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Follow.java
deleted file mode 100644
index 573ecc6e..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Follow.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Follow extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Like.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Like.java
deleted file mode 100644
index 3670293d..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Like.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Like extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Undo.java b/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Undo.java
deleted file mode 100644
index 4e87e9d0..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/activities/Undo.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.activities;
-
-import com.juick.server.api.activity.model.Activity;
-
-public class Undo extends Activity {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java
deleted file mode 100644
index 34e73be6..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Hashtag.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-public class Hashtag extends Context {
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Image.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Image.java
deleted file mode 100644
index e067f729..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Image.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-public class Image extends Context {
- private String mediaType;
-
- public String getMediaType() {
- return mediaType;
- }
-
- public void setMediaType(String mediaType) {
- this.mediaType = mediaType;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Key.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Key.java
deleted file mode 100644
index 075c51dd..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Key.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-public class Key extends Context {
- private String owner;
- private String publicKeyPem;
-
- public String getOwner() {
- return owner;
- }
-
- public void setOwner(String owner) {
- this.owner = owner;
- }
-
- public String getPublicKeyPem() {
- return publicKeyPem;
- }
-
- public void setPublicKeyPem(String publicKeyPem) {
- this.publicKeyPem = publicKeyPem;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Link.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Link.java
deleted file mode 100644
index 0c4f26dc..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Link.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-public class Link extends Context {
- private String href;
-
- public String getHref() {
- return href;
- }
-
- public void setHref(String href) {
- this.href = href;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Mention.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Mention.java
deleted file mode 100644
index bcb52d37..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Mention.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-public class Mention extends Link {
- @JsonCreator
- public Mention(@JsonProperty("href") String href, @JsonProperty("name") String name) {
- this.setHref(href);
- this.setName(name);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Note.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Note.java
deleted file mode 100644
index baad2d3b..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Note.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.juick.server.api.activity.model.Context;
-
-import java.util.List;
-
-public class Note extends Context {
- private String content;
- private String attributedTo;
- private String inReplyTo;
- private List<Image> attachment;
- private List<String> to;
- private List<String> cc;
-
- public String getContent() {
- return content;
- }
-
- public void setContent(String content) {
- this.content = content;
- }
-
- public String getAttributedTo() {
- return attributedTo;
- }
-
- public void setAttributedTo(String attributedTo) {
- this.attributedTo = attributedTo;
- }
-
- @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
- public List<Image> getAttachment() {
- return attachment;
- }
-
- public void setAttachment(List<Image> attachment) {
- this.attachment = attachment;
- }
-
- public List<String> getTo() {
- return to;
- }
-
- public void setTo(List<String> to) {
- this.to = to;
- }
-
- public List<String> getCc() {
- return cc;
- }
-
- public void setCc(List<String> cc) {
- this.cc = cc;
- }
-
- public String getInReplyTo() {
- return inReplyTo;
- }
-
- public void setInReplyTo(String inReplyTo) {
- this.inReplyTo = inReplyTo;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java
deleted file mode 100644
index 426cf331..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollection.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-public class OrderedCollection extends Context {
-
- private int totalItems;
-
- public int getTotalItems() {
- return totalItems;
- }
-
- public void setTotalItems(int totalItems) {
- this.totalItems = totalItems;
- }
- private String first;
-
- public String getFirst() {
- return first;
- }
-
- public void setFirst(String first) {
- this.first = first;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java
deleted file mode 100644
index 601919ba..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/OrderedCollectionPage.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.juick.server.api.activity.model.Context;
-
-import java.util.List;
-
-public class OrderedCollectionPage extends Context {
-
- private String partOf;
-
- private String first;
-
- private String next;
-
- private String last;
-
- private List<? extends Context> orderedItems;
-
- public String getNext() {
- return next;
- }
-
- public void setNext(String next) {
- this.next = next;
- }
-
- public List<? extends Context> getOrderedItems() {
- return orderedItems;
- }
-
- public void setOrderedItems(List<? extends Context> orderedItems) {
- this.orderedItems = orderedItems;
- }
-
- public String getPartOf() {
- return partOf;
- }
-
- public void setPartOf(String partOf) {
- this.partOf = partOf;
- }
-
- public String getFirst() {
- return first;
- }
-
- public void setFirst(String first) {
- this.first = first;
- }
-
- public String getLast() {
- return last;
- }
-
- public void setLast(String last) {
- this.last = last;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Person.java b/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Person.java
deleted file mode 100644
index 2d3a45d7..00000000
--- a/juick-server/src/main/java/com/juick/server/api/activity/model/objects/Person.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.juick.server.api.activity.model.objects;
-
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.juick.server.api.activity.model.Context;
-
-public class Person extends Context {
-
- private String name;
- private String preferredUsername;
- private Image icon;
- private String inbox;
- private String outbox;
- private String following;
- private String followers;
- private Key publicKey;
-
- @Override
- public String getType() {
- return "Person";
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
- public Image getIcon() {
- return icon;
- }
-
- public void setIcon(Image icon) {
- this.icon = icon;
- }
-
- public String getOutbox() {
- return outbox;
- }
-
- public void setOutbox(String outbox) {
- this.outbox = outbox;
- }
-
- public String getInbox() {
- return inbox;
- }
-
- public void setInbox(String inbox) {
- this.inbox = inbox;
- }
-
- public String getFollowing() {
- return following;
- }
-
- public void setFollowing(String following) {
- this.following = following;
- }
-
- public String getFollowers() {
- return followers;
- }
-
- public void setFollowers(String followers) {
- this.followers = followers;
- }
-
- @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
- public Key getPublicKey() {
- return publicKey;
- }
-
- public void setPublicKey(Key publicKey) {
- this.publicKey = publicKey;
- }
-
- public String getPreferredUsername() {
- return preferredUsername;
- }
-
- public void setPreferredUsername(String preferredUsername) {
- this.preferredUsername = preferredUsername;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/apple/AppSiteAssociation.java b/juick-server/src/main/java/com/juick/server/api/apple/AppSiteAssociation.java
deleted file mode 100644
index 81ab6960..00000000
--- a/juick-server/src/main/java/com/juick/server/api/apple/AppSiteAssociation.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.juick.server.api.apple;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collections;
-import java.util.List;
-
-@RestController
-public class AppSiteAssociation {
- @Value("${ios_app_id:}")
- private String appId;
-
- @GetMapping("/.well-known/apple-app-site-association")
- @ResponseBody
- public SiteAssociations appSiteAssociations() {
- WebCredentials webCredentials = new WebCredentials();
- webCredentials.setApps(Collections.singletonList(appId));
- SiteAssociations siteAssociations = new SiteAssociations();
- siteAssociations.setWebcredentials(webCredentials);
- return siteAssociations;
- }
-
- private class SiteAssociations {
- private WebCredentials webcredentials;
-
- public WebCredentials getWebcredentials() {
- return webcredentials;
- }
-
- public void setWebcredentials(WebCredentials webcredentials) {
- this.webcredentials = webcredentials;
- }
- }
-
- private class WebCredentials {
- private List<String> apps;
-
- public List<String> getApps() {
- return apps;
- }
-
- public void setApps(List<String> apps) {
- this.apps = apps;
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/hostmeta/HostMeta.java b/juick-server/src/main/java/com/juick/server/api/hostmeta/HostMeta.java
deleted file mode 100644
index fa4d2a3f..00000000
--- a/juick-server/src/main/java/com/juick/server/api/hostmeta/HostMeta.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.juick.server.api.hostmeta;
-
-import com.cliqset.xrd.Link;
-import com.cliqset.xrd.XRD;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collections;
-
-import static com.cliqset.xrd.XRDConstants.XRD_MEDIA_TYPE;
-
-@RestController
-public class HostMeta {
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- @GetMapping(value = "/.well-known/host-meta", produces = XRD_MEDIA_TYPE)
- public XRD hostMetaResponse() {
- Link webfinger = new Link();
- webfinger.setTemplate(String.format("%swebfinger?resource={uri}", baseUri));
- XRD xrd = new XRD();
- xrd.setLinks(Collections.singletonList(webfinger));
- return xrd;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/Feeds.java b/juick-server/src/main/java/com/juick/server/api/rss/Feeds.java
deleted file mode 100644
index c72f3a5e..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/Feeds.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss;
-
-import com.juick.User;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.inject.Inject;
-import java.util.List;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-@Controller
-public class Feeds {
-
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
-
- @RequestMapping(value = "/rss/{userName}/blog", method = RequestMethod.GET, produces = "text/xml; charset=utf-8")
- public ModelAndView getBlog(@PathVariable String userName) {
- User user = userService.getUserByName(userName);
- if (!user.isAnonymous()) {
- List<Integer> mids = messagesService.getUserBlog(user.getUid(), 0, 0);
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName("messagesView");
- modelAndView.addObject("user", user);
- modelAndView.addObject("messages", messagesService.getMessages(UserUtils.getCurrentUser(), mids));
- return modelAndView;
- }
- throw new HttpBadRequestException();
- }
-
- @RequestMapping(value = "/rss/", method = RequestMethod.GET, produces = "text/xml; charset=utf-8")
- public ModelAndView getLast(@RequestParam(value = "hours", required = false, defaultValue = "0") Integer hours) {
- List<Integer> mids = messagesService.getLastMessages(hours);
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName("messagesView");
- modelAndView.addObject("messages", messagesService.getMessages(UserUtils.getCurrentUser(),mids));
- return modelAndView;
- }
- @RequestMapping(value = "/rss/comments", method = RequestMethod.GET, produces = "text/xml; charset=utf-8")
- public ModelAndView getLastReplies(@RequestParam(value = "hours", required = false, defaultValue = "0") Integer hours) {
- ModelAndView modelAndView = new ModelAndView();
- modelAndView.setViewName("repliesView");
- modelAndView.addObject("messages", messagesService.getLastReplies(hours));
- return modelAndView;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/MessagesView.java b/juick-server/src/main/java/com/juick/server/api/rss/MessagesView.java
deleted file mode 100644
index c0ae4a97..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/MessagesView.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.server.api.rss.extension.JuickModule;
-import com.juick.server.api.rss.extension.JuickModuleImpl;
-import com.juick.util.MessageUtils;
-import com.rometools.modules.atom.modules.AtomLinkModule;
-import com.rometools.modules.atom.modules.AtomLinkModuleImpl;
-import com.rometools.modules.mediarss.MediaEntryModuleImpl;
-import com.rometools.modules.mediarss.MediaModule;
-import com.rometools.modules.mediarss.MediaModuleImpl;
-import com.rometools.modules.mediarss.types.MediaContent;
-import com.rometools.modules.mediarss.types.Metadata;
-import com.rometools.modules.mediarss.types.Thumbnail;
-import com.rometools.modules.mediarss.types.UrlReference;
-import com.rometools.rome.feed.atom.Link;
-import com.rometools.rome.feed.rss.*;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-public class MessagesView extends AbstractRssFeedView {
-
- private static final Logger logger = LoggerFactory.getLogger(MessagesView.class);
-
- @PostConstruct
- public void init() {
- setContentType("application/rss+xml;charset=UTF-8");
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected List<Item> buildFeedItems(@Nonnull Map<String, Object> model,
- @Nonnull HttpServletRequest request,
- @Nonnull HttpServletResponse response) {
- List<Message> msgs = (List<Message>)model.get("messages");
- return msgs.stream().map(this::createRssItem).collect(Collectors.toList());
- }
-
- @Override
- protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) {
- Object userObj = model.get("user");
- if (userObj != null) {
- User user = (User) userObj;
- feed.setDescription(String.format("The latest messages by @%s at Juick", user.getName()));
- String title = String.format("%s - Juick", user.getName());
- feed.setTitle(title);
- String link = String.format("http://juick.com/%s/", user.getName());
- feed.setLink(link);
- Image rssImage = new Image();
- rssImage.setUrl(String.format("http://juick.com/a/%d.png", user.getUid()));
- rssImage.setTitle(title);
- rssImage.setLink(link);
- feed.setImage(rssImage);
- String href = String.format("http://rss.juick.com/%s/blog", user.getName());
- AtomLinkModule atomLinkModule = new AtomLinkModuleImpl();
- Link atomLink = new Link();
- atomLink.setHref(href);
- atomLink.setType("application/rss+xml");
- atomLink.setRel("self");
- atomLinkModule.setLinks(Collections.singletonList(atomLink));
-
- feed.getModules().add(atomLinkModule);
- } else {
- feed.setDescription("The latest messages at Juick");
- feed.setLink("http://juick.com/");
- feed.setTitle("Juick");
- }
-
- MediaModule mediaModule = new MediaModuleImpl();
- feed.getModules().add(mediaModule);
-
-
- }
-
- private Item createRssItem(Message msg) {
- Item item = new Item();
- String messageUrl = String.format("http://juick.com/%s/%d", msg.getUser().getName(), msg.getMid());
- String messageTitle = String.format("@%s: %s", msg.getUser().getName(), MessageUtils.getTagsString(msg));
- boolean isCode = msg.getTags().stream().anyMatch(t -> t.getName().equals("code"));
- String messageDescription = isCode ? MessageUtils.formatMessageCode(StringUtils.defaultString(msg.getText()))
- : MessageUtils.formatMessage(StringUtils.defaultString(msg.getText()));
- item.setLink(messageUrl);
- //item.setGuid(messageUrl);
- item.setTitle(messageTitle);
- Description description = new Description();
- description.setType("text/html");
- description.setValue(messageDescription);
- item.setDescription(description);
- item.setPubDate(Date.from(msg.getTimestamp()));
- item.setComments(messageUrl);
- msg.getTags().stream().map(t -> {
- Category category = new Category();
- category.setValue(t.getName());
- return category;
- }).forEach(c -> item.getCategories().add(c));
- JuickModule juickModule = new JuickModuleImpl();
- juickModule.setUid(msg.getUser().getUid());
- item.getModules().add(juickModule);
- if (StringUtils.isNotEmpty(msg.getAttachmentType())) {
- String type = msg.getAttachmentType().equals("jpg") ? "image/jpeg" : "image/png";
- MediaEntryModuleImpl module = new MediaEntryModuleImpl();
- try {
- UrlReference reference = new UrlReference(MessageUtils.attachmentUrl(msg));
- MediaContent mediaContent = new MediaContent(reference);
- mediaContent.setType(type);
- Metadata metadata = new Metadata();
- metadata.setThumbnail(new Thumbnail[]{new Thumbnail(new URI(msg.getPhoto().getThumbnail()))});
- module.setMetadata(metadata);
- module.setMediaContents(new MediaContent[]{mediaContent});
- item.getModules().add(module);
- } catch (URISyntaxException e) {
- logger.error("Invalid URI", e);
- }
-
- }
- return item;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/RepliesView.java b/juick-server/src/main/java/com/juick/server/api/rss/RepliesView.java
deleted file mode 100644
index a0ab801e..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/RepliesView.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss;
-
-import com.juick.model.ResponseReply;
-import com.juick.util.MessageUtils;
-import com.rometools.modules.mediarss.MediaEntryModuleImpl;
-import com.rometools.modules.mediarss.MediaModule;
-import com.rometools.modules.mediarss.MediaModuleImpl;
-import com.rometools.modules.mediarss.types.MediaContent;
-import com.rometools.modules.mediarss.types.Metadata;
-import com.rometools.modules.mediarss.types.Thumbnail;
-import com.rometools.modules.mediarss.types.UrlReference;
-import com.rometools.rome.feed.rss.Channel;
-import com.rometools.rome.feed.rss.Description;
-import com.rometools.rome.feed.rss.Item;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-public class RepliesView extends AbstractRssFeedView {
-
- private static final Logger logger = LoggerFactory.getLogger(RepliesView.class);
-
- @PostConstruct
- public void init() {
- setContentType("application/rss+xml;charset=UTF-8");
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected @Nonnull List<Item> buildFeedItems(@Nonnull Map<String, Object> model,
- @Nonnull HttpServletRequest request,
- @Nonnull HttpServletResponse response) {
- List<ResponseReply> msgs = (List<ResponseReply>)model.get("messages");
- return msgs.stream().map(this::createRssItem).collect(Collectors.toList());
- }
-
- @Override
- protected void buildFeedMetadata(Map<String, Object> model, Channel feed, HttpServletRequest request) {
- feed.setTitle("Juick");
- feed.setLink("http://juick.com/");
- feed.setDescription("The latest comments at Juick");
- MediaModule mediaModule = new MediaModuleImpl();
- feed.getModules().add(mediaModule);
- }
-
- private Item createRssItem(ResponseReply msg) {
- Item item = new Item();
- String messageUrl = String.format("http://juick.com/m/%d#%d", msg.getMid(), msg.getRid());
- String messageTitle = String.format("@%s:", msg.getUname());
- String messageDescription = msg.isHtml() ? msg.getDescription() : MessageUtils.formatMessage(msg.getDescription());
- item.setLink(messageUrl);
- //item.setGuid(messageUrl);
- item.setTitle(messageTitle);
- Description description = new Description();
- description.setType("text/html");
- description.setValue(messageDescription);
- item.setDescription(description);
- item.setPubDate(msg.getPubDate());
- if (StringUtils.isNotEmpty(msg.getAttachmentType())) {
- String type = msg.getAttachmentType().equals("jpg") ? "image/jpeg" : "image/png";
- MediaEntryModuleImpl module = new MediaEntryModuleImpl();
- try {
- UrlReference reference = new UrlReference(
- String.format("http://i.juick.com/photos-1024/%d-%d.%s", msg.getMid(), msg.getRid(), type));
- MediaContent mediaContent = new MediaContent(reference);
- mediaContent.setType(type);
- Metadata metadata = new Metadata();
- metadata.setThumbnail(new Thumbnail[]{new Thumbnail(
- new URI(String.format("http://i.juick.com/ps/%d-%d.%s", msg.getMid(), msg.getRid(), type)))});
- module.setMetadata(metadata);
- module.setMediaContents(new MediaContent[]{mediaContent});
- item.getModules().add(module);
- } catch (URISyntaxException e) {
- logger.error("Invalid URI", e);
- }
-
- }
- return item;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModule.java b/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModule.java
deleted file mode 100644
index a4198518..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModule.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss.extension;
-
-import com.rometools.rome.feed.module.Module;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-public interface JuickModule extends Module {
-
- String URI = "http://juick.com/";
-
- Integer getUid();
-
- void setUid(Integer uid);
-
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleGenerator.java b/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleGenerator.java
deleted file mode 100644
index 90dec35f..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleGenerator.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss.extension;
-
-import com.rometools.rome.feed.module.Module;
-import com.rometools.rome.io.ModuleGenerator;
-import org.jdom2.Element;
-import org.jdom2.Namespace;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Created by vt on 13/12/2016.
- */
-public class JuickModuleGenerator implements ModuleGenerator {
-
- private static final Namespace JUICK_NS = Namespace.getNamespace("juick", JuickModule.URI);
-
- @Override
- public String getNamespaceUri() {
- return JuickModule.URI;
- }
-
- private static final Set<Namespace> NAMESPACES;
-
- static {
- Set<Namespace> nss = new HashSet<>();
- nss.add(JUICK_NS);
- NAMESPACES = Collections.unmodifiableSet(nss);
- }
-
- @Override
- public Set<Namespace> getNamespaces() {
- return NAMESPACES;
- }
-
- @Override
- public void generate(Module module, Element element) {
- // this is not necessary, it is done to avoid the namespace definition in every item.
- Element root = element;
- while (root.getParent()!=null && root.getParent() instanceof Element) {
- root = element.getParentElement();
- }
- root.addNamespaceDeclaration(JUICK_NS);
-
- JuickModule juickModule = (JuickModule) module;
- if (juickModule.getUid() > 0) {
- Element user = new Element("user", JUICK_NS);
- user.setAttribute("uid", String.valueOf(juickModule.getUid()), JUICK_NS);
- element.addContent(user);
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleImpl.java b/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleImpl.java
deleted file mode 100644
index dbdd8c85..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleImpl.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss.extension;
-
-import com.rometools.rome.feed.CopyFrom;
-import com.rometools.rome.feed.module.ModuleImpl;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-public class JuickModuleImpl extends ModuleImpl implements JuickModule {
-
- private Integer uid;
-
- public JuickModuleImpl() {
- super(JuickModule.class, JuickModule.URI);
- }
-
- @Override
- public Integer getUid() {
- return uid;
- }
-
- @Override
- public void setUid(Integer uid) {
- this.uid = uid;
- }
-
- @Override
- public Class<? extends CopyFrom> getInterface() {
- return JuickModule.class;
- }
-
- @Override
- public void copyFrom(CopyFrom obj) {
- JuickModule juickModule = (JuickModule) obj;
- setUid(juickModule.getUid());
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleParser.java b/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleParser.java
deleted file mode 100644
index a3d0e175..00000000
--- a/juick-server/src/main/java/com/juick/server/api/rss/extension/JuickModuleParser.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.rss.extension;
-
-import com.rometools.rome.feed.module.Module;
-import com.rometools.rome.io.ModuleParser;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.jdom2.Element;
-
-import java.util.Locale;
-
-/**
- * Created by vitalyster on 13.12.2016.
- */
-public class JuickModuleParser implements ModuleParser {
- @Override
- public String getNamespaceUri() {
- return JuickModule.URI;
- }
-
- @Override
- public Module parse(Element element, Locale locale) {
- JuickModuleImpl juickModule = new JuickModuleImpl();
- juickModule.setUid(NumberUtils.toInt(element.getAttributeValue("uid", JuickModule.URI), 0));
- return juickModule;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/webfinger/Resource.java b/juick-server/src/main/java/com/juick/server/api/webfinger/Resource.java
deleted file mode 100644
index 71a0ca31..00000000
--- a/juick-server/src/main/java/com/juick/server/api/webfinger/Resource.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.juick.server.api.webfinger;
-
-import com.juick.User;
-import com.juick.server.api.webfinger.model.Account;
-import com.juick.server.api.webfinger.model.Link;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.service.UserService;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.util.UriComponentsBuilder;
-import rocks.xmpp.addr.Jid;
-
-import javax.inject.Inject;
-import java.util.Collections;
-
-import static com.juick.server.api.activity.model.Context.ACTIVITY_MEDIA_TYPE;
-
-@RestController
-public class Resource {
- @Inject
- private UserService userService;
- @Value("${web_domain:localhost}")
- private String domain;
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
-
- @GetMapping("/.well-known/webfinger")
- public Account getWebResource(@RequestParam String resource) {
- if (resource.startsWith("acct:")) {
- Jid account = Jid.of(resource.substring(5));
- if (account.getDomain().equals(domain)) {
- User user = userService.getUserByName(account.getLocal());
- if (!user.isAnonymous()) {
- UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUri);
- builder.path(String.format("/u/%s", user.getName()));
- Link blog = new Link();
- blog.setRel("self");
- blog.setType(ACTIVITY_MEDIA_TYPE);
- blog.setHref(builder.toUriString());
- Account result = new Account();
- result.setSubject(resource);
- result.setLinks(Collections.singletonList(blog));
- return result;
- }
- }
- }
- throw new HttpNotFoundException();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/webfinger/model/Account.java b/juick-server/src/main/java/com/juick/server/api/webfinger/model/Account.java
deleted file mode 100644
index 892fa303..00000000
--- a/juick-server/src/main/java/com/juick/server/api/webfinger/model/Account.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.juick.server.api.webfinger.model;
-
-import java.util.List;
-
-public class Account {
- private String subject;
- private List<Link> links;
-
- public String getSubject() {
- return subject;
- }
-
- public void setSubject(String subject) {
- this.subject = subject;
- }
-
- public List<Link> getLinks() {
- return links;
- }
-
- public void setLinks(List<Link> links) {
- this.links = links;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/webfinger/model/Link.java b/juick-server/src/main/java/com/juick/server/api/webfinger/model/Link.java
deleted file mode 100644
index 48e7ab67..00000000
--- a/juick-server/src/main/java/com/juick/server/api/webfinger/model/Link.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.juick.server.api.webfinger.model;
-
-public class Link {
- private String rel;
- private String type;
- private String href;
-
- public String getRel() {
- return rel;
- }
-
- public void setRel(String rel) {
- this.rel = rel;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getHref() {
- return href;
- }
-
- public void setHref(String href) {
- this.href = href;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/webhooks/TelegramWebhook.java b/juick-server/src/main/java/com/juick/server/api/webhooks/TelegramWebhook.java
deleted file mode 100644
index 7a5cebda..00000000
--- a/juick-server/src/main/java/com/juick/server/api/webhooks/TelegramWebhook.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.api.webhooks;
-
-import com.juick.server.TelegramBotManager;
-import com.pengrad.telegrambot.BotUtils;
-import com.pengrad.telegrambot.model.Update;
-import org.apache.commons.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseStatus;
-import org.springframework.web.bind.annotation.RestController;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@ApiIgnore
-@RestController
-@ConditionalOnProperty({"telegram_token"})
-public class TelegramWebhook {
- private static final Logger logger = LoggerFactory.getLogger(TelegramWebhook.class);
- @Inject
- private TelegramBotManager telegramBotManager;
-
- @RequestMapping(value = "/api/tlgmbtwbhk", method = RequestMethod.POST)
- @ResponseStatus(value = HttpStatus.OK)
- public void processUpdate(InputStream body) throws Exception {
- String data = IOUtils.toString(body, StandardCharsets.UTF_8);
- logger.info("Telegram update: {}", data);
- Update update = BotUtils.parseUpdate(data);
- telegramBotManager.processUpdate(update);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/Info.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/Info.java
deleted file mode 100644
index c12df55f..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/Info.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.juick.server.api.xnodeinfo2;
-
-import com.juick.server.api.xnodeinfo2.model.*;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.inject.Inject;
-import java.time.Instant;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
-import java.util.Arrays;
-
-@RestController
-public class Info {
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- @Inject
- private JdbcTemplate jdbcTemplate;
-
- @GetMapping("/.well-known/x-nodeinfo2")
- public NodeInfo showNodeInfo() {
- NodeInfo nodeInfo = new NodeInfo();
- Server server = new Server();
- server.setBaseUrl(baseUri);
- server.setName("Juick");
- server.setSoftware("Juick");
- server.setVersion("2.x");
- nodeInfo.setServer(server);
- nodeInfo.setProtocols(Arrays.asList("xmpp", "activitypub", "smtp"));
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.setInbound(Arrays.asList("jabber", "mastodon", "email", "telegram"));
- serviceInfo.setOutbound(Arrays.asList("jabber", "mastodon", "telegram", "twitter", "email", "rss"));
- nodeInfo.setServices(serviceInfo);
- UserStats userStats = new UserStats();
- userStats.setTotal(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE banned=0", Integer.class));
- userStats.setActiveMonth(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE banned=0 AND last_seen > ?",
- Integer.class, ZonedDateTime.now().minus(1, ChronoUnit.MONTHS).toInstant()));
- userStats.setActiveHalfyear(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users WHERE banned=0 AND last_seen > ?",
- Integer.class, ZonedDateTime.now().minus(6, ChronoUnit.MONTHS).toInstant()));
- Usage usage = new Usage();
- usage.setUsers(userStats);
- usage.setLocalPosts(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM messages",
- Integer.class));
- usage.setLocalComments(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM replies",
- Integer.class));
- nodeInfo.setUsage(usage);
- return nodeInfo;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java
deleted file mode 100644
index 06fe354f..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/NodeInfo.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.juick.server.api.xnodeinfo2.model;
-
-import java.util.List;
-
-public class NodeInfo {
-
- private Server server;
-
- private List<String> protocols;
-
- private ServiceInfo services;
-
- public String getVersion() {
- return "1.0";
- }
-
- public Server getServer() {
- return server;
- }
-
- public void setServer(Server server) {
- this.server = server;
- }
-
- public List<String> getProtocols() {
- return protocols;
- }
-
- public void setProtocols(List<String> protocols) {
- this.protocols = protocols;
- }
-
- public ServiceInfo getServices() {
- return services;
- }
-
- public void setServices(ServiceInfo services) {
- this.services = services;
- }
-
- public boolean getOpenRegistrations() {
- return true;
- }
-
- private Usage usage;
-
- public Usage getUsage() {
- return usage;
- }
-
- public void setUsage(Usage usage) {
- this.usage = usage;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java
deleted file mode 100644
index a772d268..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Server.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.juick.server.api.xnodeinfo2.model;
-
-public class Server {
- private String baseUrl;
- private String name;
- private String software;
- private String version;
-
- public String getBaseUrl() {
- return baseUrl;
- }
-
- public void setBaseUrl(String baseUrl) {
- this.baseUrl = baseUrl;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSoftware() {
- return software;
- }
-
- public void setSoftware(String software) {
- this.software = software;
- }
-
- public String getVersion() {
- return version;
- }
-
- public void setVersion(String version) {
- this.version = version;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java
deleted file mode 100644
index 5b6d2baa..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/ServiceInfo.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.juick.server.api.xnodeinfo2.model;
-
-import java.util.List;
-
-public class ServiceInfo {
- private List<String> inbound;
- private List<String> outbound;
-
- public List<String> getInbound() {
- return inbound;
- }
-
- public void setInbound(List<String> inbound) {
- this.inbound = inbound;
- }
-
- public List<String> getOutbound() {
- return outbound;
- }
-
- public void setOutbound(List<String> outbound) {
- this.outbound = outbound;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java
deleted file mode 100644
index e04ea48b..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/Usage.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.juick.server.api.xnodeinfo2.model;
-
-public class Usage {
- private UserStats users;
- private int localPosts;
- private int localComments;
-
- public UserStats getUsers() {
- return users;
- }
-
- public void setUsers(UserStats users) {
- this.users = users;
- }
-
- public int getLocalPosts() {
- return localPosts;
- }
-
- public void setLocalPosts(int localPosts) {
- this.localPosts = localPosts;
- }
-
- public int getLocalComments() {
- return localComments;
- }
-
- public void setLocalComments(int localComments) {
- this.localComments = localComments;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java b/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java
deleted file mode 100644
index 515661e3..00000000
--- a/juick-server/src/main/java/com/juick/server/api/xnodeinfo2/model/UserStats.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.juick.server.api.xnodeinfo2.model;
-
-public class UserStats {
- private int total;
- private int activeHalfyear;
- private int activeMonth;
-
- public int getTotal() {
- return total;
- }
-
- public void setTotal(int total) {
- this.total = total;
- }
-
- public int getActiveHalfyear() {
- return activeHalfyear;
- }
-
- public void setActiveHalfyear(int activeHalfyear) {
- this.activeHalfyear = activeHalfyear;
- }
-
- public int getActiveMonth() {
- return activeMonth;
- }
-
- public void setActiveMonth(int activeMonth) {
- this.activeMonth = activeMonth;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java b/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java
deleted file mode 100644
index 9bc1b656..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientConfig.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.juick.server.configuration;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.client.SimpleClientHttpRequestFactory;
-import org.springframework.web.client.RestTemplate;
-
-import javax.inject.Inject;
-
-@Configuration
-public class ActivityPubClientConfig {
- @Inject
- ActivityPubClientErrorHandler activityPubClientErrorHandler;
- @Bean
- public RestTemplate apClient() {
- SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
- requestFactory.setOutputStreaming(false);
- RestTemplate restTemplate = new RestTemplate(requestFactory);
- restTemplate.setErrorHandler(activityPubClientErrorHandler);
- return restTemplate;
- }
-} \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientErrorHandler.java b/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientErrorHandler.java
deleted file mode 100644
index e535b3e5..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/ActivityPubClientErrorHandler.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.juick.server.configuration;
-
-import com.juick.service.activities.DeleteUserEvent;
-import org.apache.commons.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.DefaultResponseErrorHandler;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-
-@Component
-public class ActivityPubClientErrorHandler extends DefaultResponseErrorHandler {
- private static final Logger logger = LoggerFactory.getLogger(ActivityPubClientErrorHandler.class);
-
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
- @Override
- public void handleError(URI contextUri, HttpMethod method, @Nonnull ClientHttpResponse response) throws IOException {
- logger.warn("HTTP ERROR {} {} : {}", response.getStatusCode().value(),
- response.getStatusText(), IOUtils.toString(response.getBody(), StandardCharsets.UTF_8));
- if (response.getStatusCode().equals(HttpStatus.GONE)) {
- logger.warn("Server report {} is gone, deleting", contextUri.toASCIIString());
- applicationEventPublisher.publishEvent(new DeleteUserEvent(this, contextUri.toASCIIString()));
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java
deleted file mode 100644
index 5a5d2c7b..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/ApiAppConfiguration.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.configuration;
-
-import com.juick.server.WebsocketManager;
-import com.juick.server.api.rss.MessagesView;
-import com.juick.server.api.rss.RepliesView;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.Ordered;
-import org.springframework.scheduling.annotation.EnableAsync;
-import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import org.springframework.web.servlet.view.BeanNameViewResolver;
-import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
-import org.springframework.web.socket.config.annotation.EnableWebSocket;
-import org.springframework.web.socket.config.annotation.ServletWebSocketHandlerRegistry;
-import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
-import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
-import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-
-/**
- * Created by aalexeev on 11/12/16.
- */
-@Configuration
-@EnableAsync(proxyTargetClass = true)
-@EnableScheduling
-@EnableWebSocket
-public class ApiAppConfiguration implements WebMvcConfigurer, WebSocketConfigurer {
- @Inject
- private WebsocketManager websocketManager;
-
- @Override
- public void registerWebSocketHandlers(@Nonnull WebSocketHandlerRegistry registry) {
- ((ServletWebSocketHandlerRegistry) registry).setOrder(Ordered.HIGHEST_PRECEDENCE);
- registry.addHandler(websocketManager, "/ws/**").setAllowedOrigins("*");
- }
-
- @Bean
- public ServletServerContainerFactoryBean createWebSocketContainer() {
- ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
- container.setMaxTextMessageBufferSize(8192);
- container.setMaxBinaryMessageBufferSize(8192);
- return container;
- }
- @Bean
- public BeanNameViewResolver beanNameViewResolver() {
- return new BeanNameViewResolver();
- }
- @Bean
- AbstractRssFeedView messagesView() {
- return new MessagesView();
- }
- @Bean
- AbstractRssFeedView repliesView() {
- return new RepliesView();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java
deleted file mode 100644
index 23a35384..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/BaseWebConfiguration.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.configuration;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.annotation.SchedulingConfigurer;
-import org.springframework.scheduling.config.ScheduledTaskRegistrar;
-import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Created by vitalyster on 28.06.2016.
- */
-@Configuration
-public class BaseWebConfiguration implements WebMvcConfigurer, SchedulingConfigurer {
-
-
- @Override
- public void configurePathMatch(PathMatchConfigurer configurer) {
- configurer.setUseSuffixPatternMatch(false);
- }
-
- @Bean
- public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
- return new ResourceUrlEncodingFilter();
- }
-
- @Override
- public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
- taskRegistrar.setScheduler(taskExecutor());
- }
-
- @Bean(destroyMethod="shutdown")
- public Executor taskExecutor() {
- return Executors.newScheduledThreadPool(100);
- }
-
- @Bean
- public ExecutorService executorService() {
- return Executors.newCachedThreadPool();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/SapeConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/SapeConfiguration.java
deleted file mode 100644
index 9727fbb1..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/SapeConfiguration.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.configuration;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import ru.sape.Sape;
-
-/**
- * Created by vitalyster on 29.03.2017.
- */
-@Configuration
-@ConditionalOnProperty("sape_user")
-public class SapeConfiguration {
- @Value("${sape_user:}")
- private String token;
-
- @Bean
- public Sape sape() {
- return new Sape(token, "juick.com", 2000, 3600);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/SecurityConfig.java b/juick-server/src/main/java/com/juick/server/configuration/SecurityConfig.java
deleted file mode 100644
index f02083d5..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/SecurityConfig.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.configuration;
-
-import com.juick.service.UserService;
-import com.juick.service.security.HashParamAuthenticationFilter;
-import com.juick.service.security.JuickUserDetailsService;
-import com.juick.service.security.deprecated.RequestParamHashRememberMeServices;
-import com.juick.service.security.entities.JuickUser;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.authentication.HttpStatusEntryPoint;
-import org.springframework.security.web.authentication.RememberMeServices;
-import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
-import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.CorsConfigurationSource;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Created by aalexeev on 11/21/16.
- */
-@EnableWebSecurity
-public class SecurityConfig {
- @Resource
- private UserService userService;
- @Value("${auth_remember_me_key:secret}")
- private String rememberMeKey;
- @Value("${web_domain:localhost}")
- private String webDomain;
-
- private static final String COOKIE_NAME = "juick-remember-me";
-
- @Bean
- public UserDetailsService userDetailsService() {
- return new JuickUserDetailsService(userService);
- }
-
- @Configuration
- @Order(1)
- public static class ApiConfig extends WebSecurityConfigurerAdapter {
- @Value("${auth_remember_me_key:secret}")
- private String rememberMeKey;
- @Value("${web_domain:localhost}")
- private String webDomain;
- @Resource
- private UserService userService;
- ApiConfig() {
- super(true);
- }
- @Bean
- RememberMeServices apiTokenServices(){
- return new RequestParamHashRememberMeServices(rememberMeKey, userService);
- }
- @Bean
- public HashParamAuthenticationFilter apiAuthenticationFilter() {
- return new HashParamAuthenticationFilter(userService, apiTokenServices());
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.antMatcher("/api/**")
- .addFilterBefore(apiAuthenticationFilter(), BasicAuthenticationFilter.class)
- .authorizeRequests()
- .antMatchers(HttpMethod.OPTIONS).permitAll()
- .antMatchers("/api/", "/api/messages", "/api/messages/discussions", "/api/users", "/api/thread", "/api/tags", "/api/tlgmbtwbhk", "/api/fbwbhk",
- "/api/skypebotendpoint", "/api/_fblogin", "/api/_vklogin", "/api/_tglogin", "/api/inbox", "/api/u/**", "/.well-known/webfinger", "/.well-known/x-nodeinfo2", "/rss/**", "/api/events").permitAll()
- .anyRequest().hasRole("USER")
- .and()
- .anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
- .and()
- .httpBasic().authenticationEntryPoint(juickAuthenticationEntryPoint())
- .and().cors().configurationSource(corsConfigurationSource())
- .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
- .and().exceptionHandling().authenticationEntryPoint(juickAuthenticationEntryPoint())
- .and()
- .rememberMe()
- .alwaysRemember(true)
- .tokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(6 * 30))
- .rememberMeServices(apiTokenServices())
- .key(rememberMeKey)
- .and()
- .headers().defaultsDisabled().cacheControl();
- }
-
- @Bean
- public AuthenticationEntryPoint juickAuthenticationEntryPoint() {
- return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);
- }
-
- @Bean
- public CorsConfigurationSource corsConfigurationSource() {
- CorsConfiguration configuration = new CorsConfiguration();
-
- configuration.setAllowedOrigins(Collections.singletonList("*"));
- configuration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "OPTIONS", "DELETE"));
- configuration.setAllowedHeaders(Collections.singletonList("*"));
-
- UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/api/**", configuration);
-
- return source;
- }
- @Override
- public void configure(WebSecurity web) {
- web.debug(false);
- web.ignoring().antMatchers("/api/v2/api-docs", "/api/configuration/ui", "/api/swagger-resources/**",
- "/api/configuration/**", "/swagger-ui.html", "/webjars/**", "/h2-console/**");
- }
- }
-
- @Configuration
- public static class WebConfig extends WebSecurityConfigurerAdapter {
- @Value("${auth_remember_me_key:secret}")
- private String rememberMeKey;
- @Value("${web_domain:localhost}")
- private String webDomain;
- @Resource
- private UserService userService;
- @Inject
- private UserDetailsService userDetailsService;
- @Bean
- @Qualifier("www")
- public HashParamAuthenticationFilter wwwAuthenticationFilter() {
- return new HashParamAuthenticationFilter(userService, hashCookieServices());
- }
- @Bean
- @Qualifier("www")
- public RememberMeServices hashCookieServices() {
- TokenBasedRememberMeServices services = new TokenBasedRememberMeServices(
- rememberMeKey, userDetailsService);
-
- services.setCookieName(COOKIE_NAME);
- services.setCookieDomain(webDomain);
- services.setAlwaysRemember(true);
- services.setTokenValiditySeconds(6 * 30 * 24 * 3600);
- services.setUseSecureCookie(false); // TODO set true if https is supports
-
- return services;
- }
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .addFilterBefore(wwwAuthenticationFilter(), BasicAuthenticationFilter.class)
- .authorizeRequests()
- .antMatchers("/settings", "/pm/**", "/**/bl", "/_twitter", "/post", "/post2", "/comment")
- .authenticated()
- .anyRequest().permitAll()
- .and()
- .anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY)
- .and()
- .sessionManagement().invalidSessionUrl("/")
- .and()
- .logout()
- .invalidateHttpSession(true)
- .logoutUrl("/logout")
- .logoutSuccessUrl("/login?logout")
- .deleteCookies("hash", COOKIE_NAME)
- .and()
- .formLogin()
- .loginPage("/login")
- .permitAll()
- .defaultSuccessUrl("/")
- .loginProcessingUrl("/login")
- .usernameParameter("username")
- .passwordParameter("password")
- .failureUrl("/login?error=1")
- .and()
- .rememberMe()
- .rememberMeCookieDomain(webDomain).key(rememberMeKey)
- .rememberMeServices(hashCookieServices())
- .and()
- .csrf().disable()
- .headers().defaultsDisabled().cacheControl();
- }
- @Override
- public void configure(WebSecurity web) {
- web.debug(false);
- web.ignoring().antMatchers("/style*.css", "/scripts*.js", "/h2-console/**", "/.well-known/**", "/ws/**");
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/StorageConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/StorageConfiguration.java
deleted file mode 100644
index 4101f37d..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/StorageConfiguration.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.juick.server.configuration;
-
-import com.juick.service.ImagesService;
-import com.juick.service.ImagesServiceImpl;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class StorageConfiguration {
-
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
- @Bean
- public ImagesService imagesService() {
- return new ImagesServiceImpl(imgDir, tmpDir);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/TelegramConfig.java b/juick-server/src/main/java/com/juick/server/configuration/TelegramConfig.java
deleted file mode 100644
index ebd1fd15..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/TelegramConfig.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.juick.server.configuration;
-
-import com.juick.server.TelegramBotManager;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@ConditionalOnProperty(name = "telegram_token")
-public class TelegramConfig {
- @Bean
- public TelegramBotManager telegramBotManager() {
- return new TelegramBotManager();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/WwwAppConfiguration.java b/juick-server/src/main/java/com/juick/server/configuration/WwwAppConfiguration.java
deleted file mode 100644
index 72889f96..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/WwwAppConfiguration.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.configuration;
-
-import com.juick.server.www.HelpService;
-import com.juick.service.TagService;
-import com.juick.service.UserService;
-import com.mitchellbosecke.pebble.PebbleEngine;
-import com.mitchellbosecke.pebble.extension.FormatterExtension;
-import com.mitchellbosecke.pebble.loader.ClasspathLoader;
-import com.mitchellbosecke.pebble.loader.Loader;
-import com.mitchellbosecke.pebble.spring.PebbleViewResolver;
-import com.mitchellbosecke.pebble.spring.extension.SpringExtension;
-import org.apache.commons.codec.CharEncoding;
-import org.commonmark.ext.autolink.AutolinkExtension;
-import org.commonmark.node.Link;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.cache.caffeine.CaffeineCacheManager;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.ViewResolver;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-import javax.inject.Inject;
-import java.util.Collections;
-
-/**
- * Created by aalexeev on 11/22/16.
- */
-@Configuration
-@EnableCaching
-public class WwwAppConfiguration implements WebMvcConfigurer {
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Bean
- public CaffeineCacheManager cacheManager() {
- return new CaffeineCacheManager("help");
- }
-
- @Bean
- public HelpService helpService() {
- return new HelpService("help");
- }
-
- @Bean
- public Parser cmParser() {
- return Parser.builder().extensions(Collections.singletonList(AutolinkExtension.create())).build();
- }
- @Bean
- public HtmlRenderer helpRenderer() {
- return HtmlRenderer.builder()
- .attributeProviderFactory(context -> (node, tagName, attributes) -> {
- if (node instanceof Link) {
- Link link = (Link) node;
- if (link.getDestination().startsWith("/")) {
- String destination = "/" + helpService().getHelpPath() + link.getDestination();
- link.setDestination(destination);
- attributes.put("href", destination);
- }
- }
- })
- .build();
- }
- @Bean
- public Loader templateLoader() {
- return new ClasspathLoader();
- }
-
- @Bean
- public SpringExtension springExtension() {
- return new SpringExtension();
- }
-
- @Bean
- public PebbleEngine pebbleEngine() {
- boolean devToolsArePresent = false;
- try {
- Class.forName("org.springframework.boot.devtools.livereload.Connection");
- devToolsArePresent = true;
- } catch (ClassNotFoundException e) {
- // release mode
- }
- return new PebbleEngine.Builder()
- .loader(this.templateLoader())
- .cacheActive(!devToolsArePresent)
- .extension(springExtension())
- .extension(new FormatterExtension())
- .strictVariables(true)
- .build();
- }
-
- @Bean
- public ViewResolver viewResolver() {
- PebbleViewResolver viewResolver = new PebbleViewResolver();
- viewResolver.setPrefix("templates");
- viewResolver.setSuffix(".html");
- viewResolver.setPebbleEngine(pebbleEngine());
- viewResolver.setCharacterEncoding(CharEncoding.UTF_8);
- return viewResolver;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/configuration/XMPPConfig.java b/juick-server/src/main/java/com/juick/server/configuration/XMPPConfig.java
deleted file mode 100644
index 2feef286..00000000
--- a/juick-server/src/main/java/com/juick/server/configuration/XMPPConfig.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.juick.server.configuration;
-
-import com.juick.server.XMPPConnection;
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.JidConverter;
-import com.juick.server.xmpp.iq.MessageQuery;
-import com.juick.server.xmpp.router.XMPPRouter;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.DependsOn;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import rocks.xmpp.core.session.Extension;
-import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.session.debug.LogbackDebugger;
-
-import java.time.Duration;
-
-@Configuration
-@ConditionalOnProperty("xmppbot_jid")
-public class XMPPConfig {
- @Value("${hostname:localhost}")
- private String hostname;
- @Bean
- public BasicXmppSession session() {
- XmppSessionConfiguration configuration = XmppSessionConfiguration.builder()
- .extensions(Extension.of(com.juick.Message.class), Extension.of(MessageQuery.class))
- .debugger(LogbackDebugger.class)
- .defaultResponseTimeout(Duration.ofMillis(120000))
- .build();
- return BasicXmppSession.create(hostname, configuration);
- }
- @Bean
- public static ConversionService conversionService() {
- DefaultFormattingConversionService cs = new DefaultFormattingConversionService();
- cs.addConverter(new JidConverter());
- return cs;
- }
- @Bean
- public XMPPServer xmppServer() {
- return new XMPPServer();
- }
- @Bean
- public XMPPRouter xmppRouter() {
- return new XMPPRouter();
- }
- @Bean
- @DependsOn("xmppRouter")
- public XMPPConnection xmppConnection() {
- return new XMPPConnection();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/helpers/annotation/UserCommand.java b/juick-server/src/main/java/com/juick/server/helpers/annotation/UserCommand.java
deleted file mode 100644
index 4f07001c..00000000
--- a/juick-server/src/main/java/com/juick/server/helpers/annotation/UserCommand.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.helpers.annotation;
-
-import org.apache.commons.lang3.StringUtils;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Created by oxpa on 22.03.16.
- */
-@Target({ElementType.TYPE, ElementType.METHOD})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface UserCommand {
- /**
- *
- * @return a command pattern
- */
- String pattern() default StringUtils.EMPTY;
-
- /**
- *
- * @return pattern flags
- */
- int patternFlags() default 0;
-
- /**
- *
- * @return a string used in HELP command output. Basically, only 1 string
- */
- String help() default StringUtils.EMPTY;
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java b/juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java
deleted file mode 100644
index 242f2b09..00000000
--- a/juick-server/src/main/java/com/juick/server/util/HttpBadRequestException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@ResponseStatus(value = HttpStatus.BAD_REQUEST)
-public class HttpBadRequestException extends RuntimeException {
- public HttpBadRequestException() {
- super("the request was bad", null, false, false);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java b/juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java
deleted file mode 100644
index 3251ca38..00000000
--- a/juick-server/src/main/java/com/juick/server/util/HttpForbiddenException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@ResponseStatus(value = HttpStatus.FORBIDDEN)
-public class HttpForbiddenException extends RuntimeException {
- public HttpForbiddenException() {
- super(StringUtils.EMPTY, null, false, false);
- }
-
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java b/juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java
deleted file mode 100644
index f66ece8b..00000000
--- a/juick-server/src/main/java/com/juick/server/util/HttpNotFoundException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@ResponseStatus(value = HttpStatus.NOT_FOUND)
-public class HttpNotFoundException extends RuntimeException {
- public HttpNotFoundException() {
- super(StringUtils.EMPTY, null, false, false);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/HttpUtils.java b/juick-server/src/main/java/com/juick/server/util/HttpUtils.java
deleted file mode 100644
index b70eb3ad..00000000
--- a/juick-server/src/main/java/com/juick/server/util/HttpUtils.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.util;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.http.MediaType;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLConnection;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Iterator;
-import java.util.UUID;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class HttpUtils {
- private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class);
-
- public static URI receiveMultiPartFile(MultipartFile attach, String tmpDir) throws IOException {
- if (attach != null && !attach.isEmpty()) {
- ImageInputStream iis = ImageIO.createImageInputStream(attach.getInputStream());
- Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
-
- String format = StringUtils.EMPTY;
- while (readers.hasNext()) {
- ImageReader read = readers.next();
- format = read.getFormatName();
- }
- String attachmentType = attachmentTypeFromFormat(format);
- if (attachmentType.equals("jpg") || attachmentType.equals("png")) {
- String attachmentFName = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType;
- try {
- Files.write(Paths.get(tmpDir, attachmentFName),
- attach.getBytes());
- return URI.create(String.format("juick://%s", attachmentFName));
- } catch (IOException e) {
- logger.warn("file receive error", e);
- }
- }
- logger.warn("file type is unknown: {}", attach.getOriginalFilename());
- }
- return URI.create(StringUtils.EMPTY);
- }
-
- private static String attachmentTypeFromFormat(String format) throws IOException {
- if (format != null && format.equals("JPEG")) {
- return "jpg";
- } else if (format != null && format.equals("png")) {
- return "png";
- } else {
- throw new IOException("Wrong file type: " + format);
- }
- }
-
- public static String mediaType(String attachmentType) {
- return attachmentType.equals("jpg") ? MediaType.IMAGE_JPEG_VALUE : MediaType.IMAGE_PNG_VALUE;
- }
-
- public static URI downloadImage(URL url, String tmpDir) throws IOException {
- ImageInputStream iis = ImageIO.createImageInputStream(url.openStream());
- Iterator<ImageReader> readers = ImageIO.getImageReaders(iis);
-
- String format = StringUtils.EMPTY;
- while (readers.hasNext()) {
- ImageReader read = readers.next();
- format = read.getFormatName();
- }
- URLConnection urlConn;
- try {
- urlConn = url.openConnection();
- } catch (IOException e) {
- logger.error(String.format("Failed open url: %s", url.toString()));
- throw e;
- }
-
- try (InputStream is = new BufferedInputStream(urlConn.getInputStream())) {
- String attachmentType = attachmentTypeFromFormat(format);
-
- String attachmentFName = DigestUtils.md5Hex(UUID.randomUUID().toString()) + "." + attachmentType;
- Files.copy(is, Paths.get(tmpDir, attachmentFName));
- return URI.create(String.format("juick://%s", attachmentFName));
- } catch (IOException e) {
- logger.error(String.format("Failed download image by url: %s", url.toString()), e);
- throw e;
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/ImageUtils.java b/juick-server/src/main/java/com/juick/server/util/ImageUtils.java
deleted file mode 100644
index d16faf8f..00000000
--- a/juick-server/src/main/java/com/juick/server/util/ImageUtils.java
+++ /dev/null
@@ -1,175 +0,0 @@
-
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import com.juick.Attachment;
-import org.apache.commons.imaging.ImageReadException;
-import org.apache.commons.imaging.Imaging;
-import org.apache.commons.imaging.common.ImageMetadata;
-import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
-import org.apache.commons.imaging.formats.tiff.TiffField;
-import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.imgscalr.Scalr;
-import org.imgscalr.Scalr.Rotation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.FileImageInputStream;
-import javax.imageio.stream.ImageInputStream;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.util.Iterator;
-
-public class ImageUtils {
- private static final Logger logger = LoggerFactory.getLogger(ImageUtils.class);
-
- private String imgDir;
- private String tmpDir;
-
- public ImageUtils(String imgDir, String tmpDir) {
- this.imgDir = imgDir;
- this.tmpDir = tmpDir;
- }
-/**
- * Returns <code>BufferedImage</code>, same as <code>ImageIO.read()</code> does.
- *
- * <p>JPEG images with EXIF metadata are rotated according to Orientation tag.
- *
- * @param imageFile a <code>File</code> to read from.
- */
- private static BufferedImage readImageWithOrientation(File imageFile)
- throws IOException {
-
- BufferedImage image = ImageIO.read(imageFile);
- if (!FilenameUtils.getExtension(imageFile.getName()).equals("jpg")) {
- return image;
- }
-
- try {
- ImageMetadata metadata = Imaging.getMetadata(imageFile);
-
- if (metadata instanceof JpegImageMetadata) {
- JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
- TiffField orientationField = jpegMetadata.findEXIFValue(TiffTagConstants.TIFF_TAG_ORIENTATION);
-
- if (orientationField != null) {
- int orientation = orientationField.getIntValue();
- switch (orientation) {
- case TiffTagConstants.ORIENTATION_VALUE_ROTATE_90_CW:
- image = Scalr.rotate(image, Rotation.CW_90);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_ROTATE_180:
- image = Scalr.rotate(image, Rotation.CW_180);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_ROTATE_270_CW:
- image = Scalr.rotate(image, Rotation.CW_270);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL:
- image = Scalr.rotate(image, Rotation.FLIP_HORZ);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_MIRROR_VERTICAL:
- image = Scalr.rotate(image, Rotation.FLIP_VERT);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_90_CW:
- image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_90);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_MIRROR_HORIZONTAL_AND_ROTATE_270_CW:
- image = Scalr.rotate(Scalr.rotate(image, Rotation.FLIP_HORZ), Rotation.CW_270);
- break;
- case TiffTagConstants.ORIENTATION_VALUE_HORIZONTAL_NORMAL:
- default:
- // do nothing
- break;
- }
- }
- }
- } catch (ImageReadException e) {
- // failed to read metadata.
- // nothing to do here, return image as is.
- }
-
- return image;
- }
-
- public void saveImageWithPreviews(String tempFilename, String outputFilename)
- throws IOException {
- String ext = FilenameUtils.getExtension(outputFilename);
-
- Path outputImagePath = Paths.get(imgDir, "p", outputFilename);
- // this throws strange exceptions
- // Files.move(Paths.get(tmpDir, tempFilename), outputImagePath);
- FileUtils.moveFile(Paths.get(tmpDir, tempFilename).toFile(), outputImagePath.toFile());
- BufferedImage originalImage = readImageWithOrientation(outputImagePath.toFile());
-
- int width = originalImage.getWidth();
- int height = originalImage.getHeight();
- int maxDimension = (width > height) ? width : height;
- BufferedImage image1024 = (maxDimension > 1024) ? Scalr.resize(originalImage, 1024) : originalImage;
- BufferedImage image0512 = (maxDimension > 512) ? Scalr.resize(originalImage, 512) : originalImage;
- BufferedImage image0160 = (maxDimension > 160) ? Scalr.resize(originalImage, 160) : originalImage;
- ImageIO.write(image1024, ext, Paths.get(imgDir, "photos-1024", outputFilename).toFile());
- ImageIO.write(image0512, ext, Paths.get(imgDir, "photos-512", outputFilename).toFile());
- ImageIO.write(image0160, ext, Paths.get(imgDir, "ps", outputFilename).toFile());
- }
-
- public void saveAvatar(String tempFilename, int uid)
- throws IOException {
- String ext = FilenameUtils.getExtension(tempFilename);
- String originalName = String.format("%s.%s", uid, ext);
- Path originalPath = Paths.get(imgDir, "ao", originalName);
- Files.move(Paths.get(tmpDir, tempFilename), originalPath, StandardCopyOption.REPLACE_EXISTING);
- BufferedImage originalImage = ImageIO.read(originalPath.toFile());
-
- String targetExt = "png";
- String targetName = String.format("%s.%s", uid, targetExt);
- ImageIO.write(Scalr.resize(originalImage, 96), targetExt, Paths.get(imgDir, "a", targetName).toFile());
- ImageIO.write(Scalr.resize(originalImage, 32), targetExt, Paths.get(imgDir, "as", targetName).toFile());
- }
- public Attachment getAttachment(File imgFile) throws IOException {
- Attachment attachment = new Attachment();
- try (ImageInputStream stream = ImageIO.createImageInputStream(imgFile)) {
- Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
- while (iter.hasNext()) {
- ImageReader reader = iter.next();
- try {
- reader.setInput(stream);
- attachment.setWidth(reader.getWidth(reader.getMinIndex()));
- attachment.setHeight(reader.getHeight(reader.getMinIndex()));
- return attachment;
- } catch (Exception e) {
- logger.debug("Error reading {}, trying next reader", imgFile.getAbsolutePath());
- } finally {
- reader.dispose();
- }
- }
- }
-
- logger.warn("Not a known image file {}", imgFile.getAbsolutePath());
- return attachment;
- }
-} \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/server/util/TagUtils.java b/juick-server/src/main/java/com/juick/server/util/TagUtils.java
deleted file mode 100644
index cb828933..00000000
--- a/juick-server/src/main/java/com/juick/server/util/TagUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import com.juick.Tag;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-public class TagUtils {
- private TagUtils() {
- throw new IllegalStateException();
- }
-
- public static String toString(final List<Tag> tags) {
- if (CollectionUtils.isEmpty(tags))
- return StringUtils.EMPTY;
-
- return tags.stream().map(t -> "*" + t.getName())
- .collect(Collectors.joining(" "));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/UserUtils.java b/juick-server/src/main/java/com/juick/server/util/UserUtils.java
deleted file mode 100644
index 1adc85ab..00000000
--- a/juick-server/src/main/java/com/juick/server/util/UserUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.service.security.entities.JuickUser;
-import javax.annotation.Nonnull;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-/**
- * Created by aalexeev on 11/14/16.
- */
-public class UserUtils {
- private UserUtils() {
- throw new IllegalStateException();
- }
-
- public static Authentication getAuthentication() {
- return SecurityContextHolder.getContext().getAuthentication();
- }
-
- public static Object getPrincipal(final Authentication authentication) {
- return authentication == null ? null : authentication.getPrincipal();
- }
-
- @Nonnull
- public static User getCurrentUser() {
- Object principal = getPrincipal(getAuthentication());
-
- if (principal instanceof JuickUser)
- return ((JuickUser) principal).getUser();
-
- if (principal instanceof User)
- return (User) principal;
-
- return AnonymousUser.INSTANCE;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/util/WebUtils.java b/juick-server/src/main/java/com/juick/server/util/WebUtils.java
deleted file mode 100644
index 9dd628ee..00000000
--- a/juick-server/src/main/java/com/juick/server/util/WebUtils.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.util;
-
-import java.util.regex.Pattern;
-
-/**
- * Created by aalexeev on 11/28/16.
- */
-public class WebUtils {
- private WebUtils() {
- throw new IllegalStateException();
- }
-
- private static final Pattern USER_NAME_PATTERN = Pattern.compile("[a-zA-Z-_\\d]{2,16}");
-
- private static final Pattern POST_NUMBER_PATTERN = Pattern.compile("-?\\d+");
-
- private static final Pattern JID_PATTERN = Pattern.compile("^[a-zA-Z0-9\\\\-\\\\_\\\\@\\\\.]{6,64}$");
-
-
- public static boolean isPostNumber(final String aString) {
- return aString != null && POST_NUMBER_PATTERN.matcher(aString).matches();
- }
-
- public static boolean isNotPostNumber(final String aString) {
- return !isPostNumber(aString);
- }
-
- public static boolean isUserName(final String aString) {
- return aString != null && USER_NAME_PATTERN.matcher(aString).matches();
- }
-
- public static boolean isNotUserName(final String aString) {
- return !isUserName(aString);
- }
-
- public static boolean isJid(final String aString) {
- return aString != null && JID_PATTERN.matcher(aString).matches();
- }
-
- public static boolean isNotJid(final String aString) {
- return !isJid(aString);
- }
-
-
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/HelpService.java b/juick-server/src/main/java/com/juick/server/www/HelpService.java
deleted file mode 100644
index 25727962..00000000
--- a/juick-server/src/main/java/com/juick/server/www/HelpService.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.www;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.cache.annotation.Cacheable;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.regex.Pattern;
-
-/**
- * Created by aalexeev on 12/11/16.
- */
-public class HelpService {
- private static final Pattern LANG_PATTERN = Pattern.compile("[a-z]{2}");
-
- private static final Pattern PAGE_PATTERN = Pattern.compile("[a-zA-Z0-9\\-_]+");
-
- private final String helpPath;
-
-
- public HelpService(String helpPath) {
- this.helpPath = helpPath;
- }
-
- @Cacheable("help")
- public String getHelp(final String page, final String lang) {
- if (canBePage(page) && canBeLang(lang)) {
- String path = StringUtils.joinWith("/", helpPath, lang, page + ".md");
-
- try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) {
- if (is != null)
- return IOUtils.toString(is, StandardCharsets.UTF_8);
- } catch (IOException e) {
- }
- }
- return null;
- }
-
- public boolean canBePage(final String anything) {
- return anything != null && PAGE_PATTERN.matcher(anything).matches();
- }
-
- public boolean canBeLang(final String anything) {
- return anything != null && LANG_PATTERN.matcher(anything).matches();
- }
-
- public String getHelpPath() {
- return helpPath;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/WebApp.java b/juick-server/src/main/java/com/juick/server/www/WebApp.java
deleted file mode 100644
index 98327a5d..00000000
--- a/juick-server/src/main/java/com/juick/server/www/WebApp.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www;
-
-import com.juick.Tag;
-import com.juick.service.TagService;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.resource.ResourceUrlProvider;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Stream;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Component
-public class WebApp {
- @Inject
- private TagService tagService;
- @Inject
- private ResourceUrlProvider resourceUrlProvider;
-
- public List<Tag> parseTags(String tagsStr) {
- List<Tag> tags = new ArrayList<>();
- if (tagsStr != null && !tagsStr.isEmpty()) {
- Stream<String> tagsList = Arrays.stream(tagsStr.split("[ \\,]"))
- .distinct().map( t -> {
- if (t.startsWith("*")) {
- t = t.substring(1);
- }
- if (t.length() > 64) {
- t = t.substring(0, 64);
- }
- return t;
- });
- tags = tagService.getTags(tagsList, true);
- while (tags.size() > 5) {
- tags.remove(5);
- }
- }
- return tags;
- }
-
- public String getStyleUrl() {
- return resourceUrlProvider.getForLookupPath("/style.css");
- }
-
- public String getScriptsUrl() {
- return resourceUrlProvider.getForLookupPath("/scripts.js");
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/AnythingFilter.java b/juick-server/src/main/java/com/juick/server/www/controllers/AnythingFilter.java
deleted file mode 100644
index cdbeafc0..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/AnythingFilter.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.juick.server.www.controllers;
-
-import com.juick.server.util.WebUtils;
-import com.juick.service.MessagesService;
-import com.juick.service.UserService;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.springframework.stereotype.Component;
-import org.springframework.web.filter.OncePerRequestFilter;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-import org.springframework.web.util.UriComponents;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import javax.servlet.*;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-@Component
-public class AnythingFilter extends OncePerRequestFilter {
- @Inject
- private MessagesService messagesService;
- @Inject
- private UserService userService;
-
- @Override
- public void doFilterInternal(@Nonnull HttpServletRequest servletRequest,
- @Nonnull HttpServletResponse servletResponse,
- @Nonnull FilterChain filterChain) throws IOException, ServletException {
- String upgrade = servletRequest.getHeader("Connection");
- if (upgrade != null && upgrade.equals("Upgrade")) {
- filterChain.doFilter(servletRequest, servletResponse);
- return;
- }
- UriComponents components = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String anything = components.getPath().substring(1);
- int before = NumberUtils.toInt(components.getQueryParams().getFirst("before"), 0);
- if (before == 0) {
- boolean isPostNumber = WebUtils.isPostNumber(anything);
- int messageId = isPostNumber ?
- NumberUtils.toInt(anything) : 0;
-
- if (isPostNumber && anything.equals(Integer.toString(messageId))) {
- if (messageId > 0) {
- com.juick.User author = messagesService.getMessageAuthor(messageId);
-
- if (author != null) {
- servletResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
- servletResponse.setHeader("Location", "/" + author.getName() + "/" + anything);
- return;
- }
- }
- }
- com.juick.User user = userService.getUserByName(anything);
- if (user.getUid() > 0) {
- ((HttpServletResponse)servletResponse).sendRedirect("/" + user.getName() + "/");
- } else {
- filterChain.doFilter(servletRequest, servletResponse);
- }
- } else {
- com.juick.User user = userService.getUserByName(anything);
- if (!user.isAnonymous()) {
- ((HttpServletResponse) servletResponse).sendRedirect("/" + user.getName() + "/?before=" + before);
- } else {
- filterChain.doFilter(servletRequest, servletResponse);
- }
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/Help.java b/juick-server/src/main/java/com/juick/server/www/controllers/Help.java
deleted file mode 100644
index 61b58a9d..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/Help.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.www.controllers;
-
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.MessagesService;
-import com.juick.server.www.HelpService;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-
-import javax.inject.Inject;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Locale;
-import java.util.Objects;
-
-/**
- * Created by aalexeev on 11/21/16.
- */
-@Controller
-public class Help {
- @Inject
- private HelpService helpService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private Parser cmParser;
- @Inject
- private HtmlRenderer helpRenderer;
-
- @GetMapping({"/help/", "/help", "/help/{langOrPage}", "/help/{lang}/{page}"})
- public String showHelp(
- Locale locale,
- @PathVariable(required = false, name = "lang") String lang,
- @PathVariable(required = false, name = "page") String page,
- @PathVariable(required = false, name = "langOrPage") String langOrPage,
- Model model) throws IOException, URISyntaxException {
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- String navigation = null;
-
- if (langOrPage != null) {
- if (helpService.canBeLang(langOrPage)) {
- navigation = helpService.getHelp("navigation", langOrPage);
- if (navigation != null)
- lang = langOrPage;
- }
-
- if (navigation == null && helpService.canBePage(langOrPage))
- page = langOrPage;
- }
-
- if (lang == null) {
- lang = locale.getLanguage();
- }
-
- String content = helpService.getHelp(page, lang);
- if (content == null && !Objects.equals("tos", page))
- content = helpService.getHelp("tos", lang);
-
- if (navigation == null)
- navigation = helpService.getHelp("navigation", lang);
-
- if (content == null || navigation == null)
- throw new HttpNotFoundException();
-
- model.addAttribute("navigation", helpRenderer.render(cmParser.parse(navigation)));
- model.addAttribute("content", helpRenderer.render(cmParser.parse(content)));
- model.addAttribute("visitor", visitor);
-
- return "views/help";
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/Login.java b/juick-server/src/main/java/com/juick/server/www/controllers/Login.java
deleted file mode 100644
index d933934e..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/Login.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.juick.server.util.UserUtils;
-import com.juick.service.UserService;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import javax.inject.Inject;
-
-/**
- * @author Ugnich Anton
- */
-@Controller
-public class Login {
- @Inject
- private UserService userService;
-
- @GetMapping("/login")
- public String getloginForm(@RequestParam(required = false, defaultValue = "true") boolean redirect) {
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- if (!visitor.isAnonymous()) {
- return redirect ? "redirect:/" : "redirect:/login/success";
- }
- return "views/login";
- }
- @GetMapping("/login/success")
- public String getSuccessLogin(ModelMap model) {
- model.addAttribute("hash", userService.getHashByUID(UserUtils.getCurrentUser().getUid()));
- return "views/login_success";
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/MessagesWWW.java b/juick-server/src/main/java/com/juick/server/www/controllers/MessagesWWW.java
deleted file mode 100644
index 0708e27f..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/MessagesWWW.java
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.formatters.PlainTextFormatter;
-import com.juick.server.Utils;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.server.util.UserUtils;
-import com.juick.server.util.WebUtils;
-import com.juick.service.*;
-import com.juick.util.MessageUtils;
-import org.apache.commons.codec.CharEncoding;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.text.StringEscapeUtils;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
-import org.springframework.web.util.UriComponents;
-import ru.sape.Sape;
-
-import javax.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Controller
-public class MessagesWWW {
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private Optional<Sape> sape;
- @Inject
- private PMQueriesService pmQueriesService;
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private ApplicationEventPublisher applicationEventPublisher;
-
- void fillUserModel(ModelMap model, com.juick.User user, com.juick.User visitor) {
- model.addAttribute("user", user);
- model.addAttribute("isSubscribed", userService.isSubscribed(visitor.getUid(), user.getUid()));
- model.addAttribute("isInBL", userService.isInBL(visitor.getUid(), user.getUid()));
- model.addAttribute("isInBLAny", userService.isInBLAny(user.getUid(), visitor.getUid()));
- model.addAttribute("statsIRead", userService.getUserFriends(user.getUid()).size());
- model.addAttribute("statsMyReaders", userService.getStatsMyReaders(user.getUid()));
- model.addAttribute("statsMyBL", userService.getUserBLUsers(user.getUid()).size());
- model.addAttribute("statsMessages", userService.getStatsMessages(user.getUid()));
- model.addAttribute("statsReplies", userService.getStatsReplies(user.getUid()));
- model.addAttribute("iread", userService.getUserReadLeastPopular(user.getUid(), 8));
- model.addAttribute("tagStats", tagService.getUserTagStats(user.getUid())
- .stream().sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).limit(20).map(t -> t.getTag().getName()).collect(Collectors.toList()));
- }
-
- @GetMapping("/")
- protected String doGet(
- @RequestParam(required = false) String tag,
- @RequestParam(name = "show", required = false) String paramShow,
- @RequestParam(name = "search", required = false) String paramSearch,
- @RequestParam(name = "before", required = false, defaultValue = "0") Integer paramBefore,
- @RequestParam(name = "to", required = false, defaultValue = "0") Long paramTo,
- @RequestParam(name = "page", required = false, defaultValue = "0") Integer page,
- @CookieValue(name = "sape_cookie", required = false, defaultValue = StringUtils.EMPTY) String sapeCookie,
- ModelMap model) throws IOException {
- if (tag != null) {
- return "redirect:/tag/" + URLEncoder.encode(tag, CharEncoding.UTF_8);
- }
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- if (paramSearch != null && paramSearch.length() > 64) {
- paramSearch = null;
- }
-
- model.addAttribute("discover", false);
-
- String title;
- List<Integer> mids;
-
- if (paramSearch != null) {
- title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch);
- mids = messagesService.getSearch(visitor, Utils.encodeSphinx(paramSearch), page);
- } else if (paramShow == null) {
- title = "Обсуждения";
- mids = messagesService.getDiscussions(visitor.getUid(), paramTo);
- } else if (paramShow.equals("top")) {
- title = "Популярные";
- mids = messagesService.getPopular(visitor.getUid(), paramBefore);
- model.addAttribute("discover", true);
- } else if (paramShow.equals("my") && !visitor.isAnonymous()) {
- title = "Моя лента";
- mids = messagesService.getMyFeed(visitor.getUid(), paramBefore, true);
- } else if (paramShow.equals("private") && !visitor.isAnonymous()) {
- title = "Приватные";
- mids = messagesService.getPrivate(visitor.getUid(), paramBefore);
- } else if (paramShow.equals("discuss")) {
- return "redirect:/";
- } else if (paramShow.equals("recommended") && !visitor.isAnonymous()) {
- title = "Рекомендации";
- mids = messagesService.getRecommended(visitor.getUid(), paramBefore);
- } else if (paramShow.equals("photos")) {
- title = "Фотографии";
- mids = messagesService.getPhotos(visitor.getUid(), paramBefore);
- model.addAttribute("discover", true);
- } else if (paramShow.equals("all")) {
- title = "Все сообщения";
- mids = messagesService.getAll(visitor.getUid(), paramBefore);
- model.addAttribute("discover", true);
- } else {
- throw new HttpNotFoundException();
- }
-
- String head = "<meta name=\"Description\" content=\"" + title + "\" />\n";;
-
- if (paramBefore > 0 || paramShow != null) {
- head = "<meta name=\"robots\" content=\"noindex\"/>";
- }
- model.addAttribute("title", title);
- model.addAttribute("headers", head);
- model.addAttribute("visitor", visitor);
- model.addAttribute("noindex", !(paramShow == null && paramBefore == 0));
- List<com.juick.Message> msgs = messagesService.getMessages(visitor, mids);
-
- if (!visitor.isAnonymous()) {
- fillUserModel(model, visitor, visitor);
- List<Integer> unread = messagesService.getUnread(visitor);
- visitor.setUnreadCount(unread.size());
- List<Integer> blUIDs = userService.checkBL(visitor.getUid(),
- msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList()));
- msgs.forEach(m -> {
- m.ReadOnly |= blUIDs.contains(m.getUser().getUid());
- m.setUnread(unread.contains(m.getMid()));
- });
- }
- model.addAttribute("msgs", msgs);
- model.addAttribute("tags", tagService.getPopularTags());
- model.addAttribute("headers", head);
- model.addAttribute("showAdv",
- paramShow == null && paramBefore == 0 && paramSearch == null && visitor.isAnonymous());
- if (mids.size() >= 20) {
- String nextpage = (paramShow == null) ? "?to=" + msgs.get(msgs.size() - 1).getUpdated().toEpochMilli() : paramSearch != null ? String.format("?page=%d", page + 1) : "?before=" + mids.get(mids.size() - 1);
- if (paramShow != null) {
- nextpage += "&amp;show=" + paramShow;
- }
- if (paramSearch != null) {
- nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8);
- }
- model.addAttribute("nextpage", nextpage);
- }
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
- String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
- model.addAttribute("links", links);
- }
- return "views/index";
- }
-
- @GetMapping(path = "/{uname}/", headers = "Connection!=Upgrade")
- protected String doGetBlog(
- @RequestParam(required = false, name = "show") String paramShow,
- @RequestParam(required = false, name = "tag") String paramTagStr,
- @RequestParam(required = false, name = "search") String paramSearch,
- @RequestParam(required = false, name = "page", defaultValue = "0") Integer page,
- @PathVariable String uname,
- @RequestParam(required = false, defaultValue = "0") Integer before,
- @CookieValue(name = "sape_cookie", required = false, defaultValue = StringUtils.EMPTY) String sapeCookie,
- ModelMap model) throws IOException {
- com.juick.User user = userService.getUserByName(uname);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (user.isBanned() || user.isAnonymous()) {
- throw new HttpNotFoundException();
- }
-
- List<Integer> mids;
-
- com.juick.Tag paramTag = null;
- if (paramTagStr != null) {
- if (paramTagStr.length() < 64) {
- paramTag = tagService.getTag(paramTagStr, false);
- }
- if (paramTag == null) {
- throw new HttpNotFoundException();
- } else if (!paramTag.getName().equals(paramTagStr)) {
- String url = user.getName() + "/?tag=" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
- return "redirect:/" + url;
- }
- }
- if (paramSearch != null && paramSearch.length() > 64) {
- paramSearch = null;
- }
-
- int privacy = 0;
- if (!visitor.isAnonymous()) {
- if (user.getUid() == visitor.getUid() || visitor.getUid() == 1) {
- privacy = -3;
- } else if (userService.isInWL(user.getUid(), visitor.getUid())) {
- privacy = -2;
- }
- }
-
- String title;
- if (paramShow == null) {
- if (paramTag != null) {
- title = "Блог " + user.getName() + ": *" + StringEscapeUtils.escapeHtml4(paramTag.getName());
- mids = messagesService.getUserTag(user.getUid(), paramTag.TID, privacy, before);
- } else if (paramSearch != null) {
- title = "Блог " + user.getName() + ": " + StringEscapeUtils.escapeHtml4(paramSearch);
- mids = messagesService.getUserSearch(visitor, user.getUid(), Utils.encodeSphinx(paramSearch), privacy, page);
- } else {
- title = "Блог " + user.getName();
- mids = messagesService.getUserBlog(user.getUid(), privacy, before);
- }
- } else if (paramShow.equals("recomm")) {
- title = "Рекомендации " + user.getName();
- mids = messagesService.getUserRecommendations(user.getUid(), before);
- } else if (paramShow.equals("photos")) {
- title = "Фотографии " + user.getName();
- mids = messagesService.getUserPhotos(user.getUid(), privacy, before);
- } else {
- throw new HttpNotFoundException();
- }
-
- String head = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" +
- user.getName() + "\" href=\"//rss.juick.com/" + user.getName() + "/blog\"/>";
- head += "<meta name=\"Description\" content=\"" + title + "\" />\n";
- if (paramTag != null && tagService.getTagNoIndex(paramTag.TID)) {
- head += "<meta name=\"robots\" content=\"noindex,nofollow\"/>";
- } else if (before > 0 || paramShow != null) {
- head += "<meta name=\"robots\" content=\"noindex\"/>";
- }
- model.addAttribute("pageUrl", "http://juick.com/" + user.getName());
- model.addAttribute("title", title);
- model.addAttribute("headers", head);
- model.addAttribute("visitor", visitor);
- model.addAttribute("noindex", paramShow == null && before == 0);
- fillUserModel(model, user, visitor);
- model.addAttribute("paramTag", paramTag);
- List<com.juick.Message> msgs = messagesService.getMessages(visitor, mids);
-
- if (!visitor.isAnonymous()) {
- List<Integer> unread = messagesService.getUnread(visitor);
- visitor.setUnreadCount(unread.size());
- List<Integer> blUIDs = userService.checkBL(visitor.getUid(),
- msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList()));
- msgs.forEach(m -> {
- m.ReadOnly |= blUIDs.contains(m.getUser().getUid());
- m.setUnread(unread.contains(m.getMid()));
- });
- }
- model.addAttribute("msgs", msgs);
- model.addAttribute("headers", head);
- model.addAttribute("showAdv",
- paramShow == null && before == 0 && paramSearch == null && visitor.getUid() == 0);
- if (mids.size() >= 20) {
- String nextpage = paramSearch != null ? String.format("?page=%d", page + 1) : "?before=" + mids.get(mids.size() - 1);
- if (paramShow != null) {
- nextpage += "&amp;show=" + paramShow;
- }
- if (paramSearch != null) {
- nextpage += "&amp;search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8);
- }
- if (paramTag != null) {
- nextpage += "&amp;tag=" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8);
- }
- model.addAttribute("nextpage", nextpage);
- }
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
- String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
- model.addAttribute("links", links);
- }
- return "views/blog";
- }
-
- @GetMapping("/{uname}/tags")
- protected String doGetTags(@PathVariable String uname, ModelMap model) throws IOException {
- com.juick.User user = userService.getUserByName(uname);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isBanned()) {
- throw new HttpNotFoundException();
- }
-
- model.addAttribute("title", "Теги " + user.getName());
- model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex,nofollow\"/>");
- model.addAttribute("visitor", visitor);
- fillUserModel(model, user, visitor);
- model.addAttribute("tags", tagService.getUserTagStats(user.getUid()).stream()
- .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).map(t -> t.getTag().getName()).collect(Collectors.toList()));
-
- return "views/blog_tags";
- }
-
- @GetMapping("/{uname}/friends")
- protected String doGetFriends(@PathVariable String uname, ModelMap model) throws IOException {
- com.juick.User user = userService.getUserByName(uname);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isBanned()) {
- throw new HttpNotFoundException();
- }
- model.addAttribute("title", "Подписки " + user.getName());
- model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex\"/>");
- model.addAttribute("visitor", visitor);
- fillUserModel(model, user, visitor);
- model.addAttribute("users", userService.getUserFriends(user.getUid()));
-
- return "views/users";
- }
-
- @GetMapping("/{uname}/readers")
- protected String doGetReaders(@PathVariable String uname, ModelMap model) throws IOException {
- com.juick.User user = userService.getUserByName(uname);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isBanned()) {
- throw new HttpForbiddenException();
- }
- model.addAttribute("title", "Читатели " + user.getName());
- model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex\"/>");
- model.addAttribute("visitor", visitor);
- fillUserModel(model, user, visitor);
- model.addAttribute("users", userService.getUserReaders(user.getUid()));
-
- return "views/users";
- }
-
- @GetMapping("/{uname}/bl")
- protected String doGetBL(@PathVariable String uname, ModelMap model) throws IOException {
- com.juick.User user = userService.getUserByName(uname);
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isBanned() || visitor.getUid() != user.getUid()) {
- throw new HttpForbiddenException();
- }
- model.addAttribute("title", "Черный список " + user.getName());
- model.addAttribute("headers", "<meta name=\"robots\" content=\"noindex\"/>");
- model.addAttribute("visitor", visitor);
- fillUserModel(model, user, visitor);
- model.addAttribute("users", userService.getUserBLUsers(user.getUid()));
-
- return "views/users";
- }
- @GetMapping("/tag/{tagName}")
- protected String tagAction(HttpServletRequest request,
- @PathVariable String tagName,
- @CookieValue(name = "sape_cookie", required = false, defaultValue = StringUtils.EMPTY) String sapeCookie,
- @RequestParam(required = false, defaultValue = "0") int before,
- ModelMap model) throws IOException {
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- String paramTagStr = StringEscapeUtils.unescapeHtml4(tagName);
- com.juick.Tag paramTag = tagService.getTag(paramTagStr, false);
- if (paramTag == null) {
- throw new HttpNotFoundException();
- } else if (paramTag.SynonymID > 0 && paramTag.TID != paramTag.SynonymID) {
- com.juick.Tag synTag = tagService.getTag(paramTag.SynonymID);
- String url = "/tag/" + URLEncoder.encode(StringEscapeUtils.escapeHtml4(synTag.getName()), CharEncoding.UTF_8);
- if (request.getQueryString() != null) {
- url += "?" + request.getQueryString();
- }
- return "redirect:" + url;
- } else if (!paramTag.getName().equals(paramTagStr)) {
- String url = "/tag/" + URLEncoder.encode(StringEscapeUtils.escapeHtml4(paramTag.getName()), CharEncoding.UTF_8);
- if (request.getQueryString() != null) {
- url += "?" + request.getQueryString();
- }
- return "redirect:" + url;
- }
-
- String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName());
- model.addAttribute("title", title);
- List<Integer> mids = messagesService.getTag(paramTag.TID, visitor.getUid(), before, (visitor.isAnonymous()) ? 40 : 20);
- List<com.juick.Message> msgs = messagesService.getMessages(visitor, mids);
- if (!visitor.isAnonymous()) {
- List<Integer> unread = messagesService.getUnread(visitor);
- visitor.setUnreadCount(unread.size());
- List<Integer> blUIDs = userService.checkBL(
- visitor.getUid(),
- msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())
- );
- msgs.forEach(m -> {
- m.ReadOnly |= blUIDs.contains(m.getUser().getUid());
- m.setUnread(unread.contains(m.getMid()));
- });
- fillUserModel(model, visitor, visitor);
- }
-
- String head = StringUtils.EMPTY;
- if (tagService.getTagNoIndex(paramTag.TID)) {
- head = "<meta name=\"robots\" content=\"noindex,nofollow\"/>";
- } else if (before > 0 || mids.size() < 5) {
- head = "<meta name=\"robots\" content=\"noindex\"/>";
- }
- model.addAttribute("headers", head);
- model.addAttribute("visitor", visitor);
- model.addAttribute("tag", paramTag);
- model.addAttribute("title", title);
- model.addAttribute("msgs", msgs);
- model.addAttribute("tags", tagService.getPopularTags());
- model.addAttribute("noindex", before > 0);
- model.addAttribute("showAdv", before == 0 && visitor.isAnonymous());
- model.addAttribute("isSubscribed", tagService.isSubscribed(visitor, paramTag));
- model.addAttribute("isInBL", tagService.isInBL(visitor, paramTag));
- if (mids.size() >= 20) {
- String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8) + "?before=" + mids.get(mids.size() - 1);
- model.addAttribute("nextpage", nextpage);
- }
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
- String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
- model.addAttribute("links", links);
- }
- return "views/index";
- }
- @GetMapping("/pm/inbox")
- protected String doGetInbox(ModelMap model) {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- return "redirect:/login";
- }
- String title = "PM: Inbox";
- List<com.juick.Message> msgs = pmQueriesService.getLastPMInbox(visitor.getUid());
- fillUserModel(model, visitor, visitor);
- model.addAttribute("title", title);
- model.addAttribute("visitor", visitor);
- model.addAttribute("msgs", msgs);
- model.addAttribute("tags", tagService.getPopularTags());
- return "views/pm_inbox";
- }
-
- @GetMapping("/pm/sent")
- protected String doGetSent(@RequestParam(required = false) String uname,
- ModelMap model) {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- return "redirect:/login";
- }
- String title = "PM: Sent";
- List<com.juick.Message> msgs = pmQueriesService.getLastPMSent(visitor.getUid());
-
- if (WebUtils.isNotUserName(uname)) {
- uname = StringUtils.EMPTY;
- }
- fillUserModel(model, visitor, visitor);
- model.addAttribute("title", title);
- model.addAttribute("visitor", visitor);
- model.addAttribute("msgs", msgs);
- model.addAttribute("tags", tagService.getPopularTags());
- model.addAttribute("uname", uname);
- return "views/pm_sent";
- }
- @GetMapping(value = "/{uname}/{mid}", produces = MediaType.TEXT_HTML_VALUE)
- protected String threadAction(ModelMap model,
- @PathVariable String uname,
- @PathVariable int mid,
- @CookieValue(name = "sape_cookie",
- required = false, defaultValue = StringUtils.EMPTY) String sapeCookie) {
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- if (!messagesService.canViewThread(mid, visitor.getUid())) {
- throw new HttpForbiddenException();
- }
-
- com.juick.Message msg = messagesService.getMessage(mid);
-
- if (msg == null || msg.getUser().isBanned()) {
- throw new HttpNotFoundException();
- }
-
- com.juick.User user = userService.getUserByName(uname);
- if (user.isAnonymous() || !msg.getUser().equals(user)) {
- return String.format("redirect:/%s/%d", msg.getUser().getName(), mid);
- }
- msg.VisitorCanComment = !visitor.isAnonymous();
- List<com.juick.Message> replies = messagesService.getReplies(visitor, msg.getMid());
- // this should be after getReplies to mark thread as read
- fillUserModel(model, user, visitor);
- if (!visitor.isAnonymous()) {
- List<Integer> unread = messagesService.getUnread(visitor);
- visitor.setUnreadCount(unread.size());
- boolean isMsgAuthor = visitor.getUid() == msg.getUser().getUid();
- boolean isInBL = userService.isInBLAny(msg.getUser().getUid(), visitor.getUid());
- msg.VisitorCanComment = isMsgAuthor || !(msg.ReadOnly || isInBL);
- }
- model.addAttribute("msg", msg);
-
- String title = msg.getUser().getName() + ": " + MessageUtils.getTagsString(msg);
-
- model.addAttribute("title", title);
- model.addAttribute("visitor", visitor);
- String headers = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" + msg.getUser().getName() + "\" href=\"//rss.juick.com/" + msg.getUser().getName() + "/blog\"/>";
- String pageUrl = "https://juick.com/" + msg.getUser().getName() + "/" + msg.getMid();
- if (msg.Hidden) {
- headers += "<meta name=\"robots\" content=\"noindex\"/>";
- }
- String cardType = StringUtils.isNotEmpty(msg.getAttachmentType()) ? "summary_large_image" : "summary";
- if (StringUtils.isNotEmpty(msg.getAttachmentType())) {
- // additional check in case of broken images
- if (msg.getAttachment() != null) {
- String msgImage = msg.getAttachment().getMedium().getUrl();
- headers += "<meta property=\"og:image\" content=\"" + msgImage + "\" />";
- }
- } else {
- String msgImage ="https://i.juick.com/a/" + msg.getUser().getUid() + ".png";
- headers += "<meta property=\"og:image\" content=\"" + msgImage + "\" />";
- }
- model.addAttribute("ogtype", "article");
- String cardDescription = StringEscapeUtils.escapeHtml4(PlainTextFormatter.formatTwitterCard(msg));
- headers += "<meta name=\"twitter:card\" content=\"" + cardType + "\" />\n" +
- "<meta name=\"twitter:site\" content=\"@juick\" />\n" +
- "<meta property=\"og:url\" content=\"" + pageUrl + "\" />\n" +
- "<meta property=\"og:title\" content=\"" + msg.getUser().getName() + " at Juick\" />\n" +
- "<meta property=\"og:description\" content=\"" + cardDescription + "\" />\n" +
- "<meta name=\"Description\" content=\"" + cardDescription + "\" />\n";
- String twitterName = crosspostService.getTwitterName(msg.getUser().getUid());
- if (StringUtils.isNotEmpty(twitterName)) {
- headers += "<meta name=\"twitter:creator\" content=\"@" + twitterName + "\" />\n";
- }
- if (msg.getTags().size() > 0) {
- headers += "<meta name=\"Keywords\" content=\"" + msg.getTags().stream().map(Tag::getName)
- .collect(Collectors.joining(", ")) + "\" />\n";
- }
- model.addAttribute("headers", headers);
- model.addAttribute("visitorSubscribed", messagesService.isSubscribed(visitor.getUid(), msg.getMid()));
- model.addAttribute("visitorInBL", userService.isInBL(msg.getUser().getUid(), visitor.getUid()));
- model.addAttribute("recomm", messagesService.getMessageRecommendations(msg.getMid()));
- List<Integer> blUIDs = new ArrayList<>();
- for (Message reply : replies) {
- if (reply.getUser().getUid() != msg.getUser().getUid()
- && !blUIDs.contains(reply.getUser().getUid())) {
- blUIDs.add(reply.getUser().getUid());
- }
- reply.VisitorCanComment = !visitor.isAnonymous();
- if (!visitor.isAnonymous()) {
- boolean isMsgAuthor = visitor.getUid() == msg.getUser().getUid();
- boolean isReplyAuthor = visitor.getUid() == reply.getUser().getUid();
- reply.VisitorCanComment = isMsgAuthor || (!msg.ReadOnly
- && msg.VisitorCanComment && (isReplyAuthor || !userService.isInBLAny(visitor.getUid(), reply.getUser().getUid())));
- }
- }
- model.addAttribute("replies", replies);
- model.addAttribute("showAdv", visitor.isAnonymous());
- UriComponents builder = ServletUriComponentsBuilder.fromCurrentRequestUri().build();
- String queryString = builder.getQuery();
- String requestURI = builder.toUri().getPath();
- if (sape.isPresent() && visitor.isAnonymous() && queryString == null) {
- String links = sape.get().getPageLinks(requestURI, sapeCookie).render();
- model.addAttribute("links", links);
- }
- return "views/thread";
- }
-
- // when message id is not fit to int
- @ExceptionHandler(NumberFormatException.class)
- public ResponseEntity<String> notFoundAction() {
- return new ResponseEntity<>(HttpStatus.NOT_FOUND);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/NewMessage.java b/juick-server/src/main/java/com/juick/server/www/controllers/NewMessage.java
deleted file mode 100644
index 6b5938a5..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/NewMessage.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.juick.server.util.UserUtils;
-import com.juick.service.TagService;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.text.StringEscapeUtils;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import javax.inject.Inject;
-import java.util.stream.Collectors;
-
-/**
- * @author Ugnich Anton
- */
-@Controller
-public class NewMessage {
-
- @Inject
- private TagService tagService;
- @GetMapping("/post")
- protected String postAction(@RequestParam(required = false) String body, ModelMap model) {
- com.juick.User visitor = UserUtils.getCurrentUser();
- model.addAttribute("title", "Написать");
- model.addAttribute("headers", "");
- model.addAttribute("visitor", visitor);
- if (body == null) {
- body = StringUtils.EMPTY;
- } else {
- if (body.length() > 4096) {
- body = body.substring(0, 4096);
- }
- body = StringEscapeUtils.escapeHtml4(body);
- }
- model.addAttribute("body", body);
- model.addAttribute("visitor", visitor);
- model.addAttribute("tags", tagService.getUserTagStats(visitor.getUid()).stream()
- .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).map(t -> t.getTag().getName()).collect(Collectors.toList()));
- return "views/post";
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/Settings.java b/juick-server/src/main/java/com/juick/server/www/controllers/Settings.java
deleted file mode 100644
index cc8f43eb..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/Settings.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.juick.User;
-import com.juick.model.NotifyOpts;
-import com.juick.model.UserInfo;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.HttpUtils;
-import com.juick.server.util.UserUtils;
-import com.juick.service.*;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.multipart.MultipartFile;
-
-import javax.inject.Inject;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Controller
-public class Settings {
- private static final Logger logger = LoggerFactory.getLogger(Settings.class);
-
- @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String imgDir;
- @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}")
- private String tmpDir;
- @Inject
- private TagService tagService;
- @Inject
- private UserService userService;
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private SubscriptionService subscriptionService;
- @Inject
- private EmailService emailService;
- @Inject
- private TelegramService telegramService;
- @Inject
- private ImagesService imagesService;
-
- @GetMapping("/settings")
- protected String doGet(HttpServletRequest request, HttpServletResponse response, ModelMap model) throws IOException {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- response.sendRedirect("/login");
- }
- List<String> pages = Arrays.asList("main", "password", "about", "auth-email", "privacy");
- String page = request.getParameter("page");
- if (StringUtils.isEmpty(page) || !pages.contains(page)) {
- page = "main";
- }
-
- model.addAttribute("title", "Настройки");
- model.addAttribute("visitor", visitor);
- model.addAttribute("tags", tagService.getPopularTags());
- model.addAttribute("auths", userService.getAuthCodes(visitor));
- model.addAttribute("email_active", emailService.getNotificationsEmail(visitor.getUid()));
- model.addAttribute("ehash", userService.getEmailHash(visitor));
- model.addAttribute("emails", userService.getEmails(visitor));
- model.addAttribute("jids", userService.getAllJIDs(visitor));
- List<String> hours = IntStream.rangeClosed(0, 23).boxed()
- .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList());
- model.addAttribute("hours", hours);
- model.addAttribute("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid()));
- model.addAttribute("twitter_name", crosspostService.getTwitterName(visitor.getUid()));
- model.addAttribute("telegram_name", crosspostService.getTelegramName(visitor.getUid()));
- model.addAttribute("notify_options", subscriptionService.getNotifyOptions(visitor));
- model.addAttribute("userinfo", userService.getUserInfo(visitor));
- if (page.equals("auth-email")) {
- if (emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("code"))) {
- ;
- model.addAttribute("result", "OK!");
- } else {
- model.addAttribute("result", "Sorry, code unknown.");
- }
- }
- return String.format("views/settings_%s", page);
- }
-
- @PostMapping("/settings")
- protected String doPost(HttpServletRequest request, HttpServletResponse response,
- @RequestParam(required = false) MultipartFile avatar,
- ModelMap model)
- throws IOException {
- com.juick.User visitor = UserUtils.getCurrentUser();
- if (visitor.isAnonymous()) {
- throw new HttpBadRequestException();
- }
- List<String> pages = Arrays.asList("main", "password", "about", "email", "email-add", "email-del",
- "email-subscr", "auth-email", "privacy", "jid-del", "twitter-del", "telegram-del", "facebook-disable",
- "facebook-enable", "vk-del");
- String page = request.getParameter("page");
- if (StringUtils.isEmpty(page) || !pages.contains(page)) {
- throw new HttpBadRequestException();
- }
- String result = StringUtils.EMPTY;
- switch (page) {
- case "password":
- if (userService.updatePassword(visitor, request.getParameter("password"))) {
- result = "<p>Password has been changed.</p>";
- String hash = userService.getHashByUID(visitor.getUid());
- Cookie c = new Cookie("hash", hash);
- c.setMaxAge(365 * 24 * 60 * 60);
- response.addCookie(c);
- }
- break;
- case "main":
- NotifyOpts opts = new NotifyOpts();
- opts.setRepliesEnabled(StringUtils.isNotEmpty(request.getParameter("jnotify")));
- opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(request.getParameter("subscr_notify")));
- opts.setRecommendationsEnabled(StringUtils.isNotEmpty(request.getParameter("recomm")));
- if (subscriptionService.setNotifyOptions(visitor, opts)) {
- result = "<p>Notification options has been updated</p>";
- }
- break;
- case "about":
- UserInfo info = new UserInfo();
- info.setFullName(request.getParameter("fullname"));
- info.setCountry(request.getParameter("country"));
- info.setUrl(request.getParameter("url"));
- info.setDescription(request.getParameter("descr"));
- String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir).getHost();
- if (StringUtils.isNotEmpty(avatarTmpPath)) {
- imagesService.saveAvatar(avatarTmpPath, visitor.getUid());
- }
- if (userService.updateUserInfo(visitor, info)) {
- result = String.format("<p>Your info is updated.</p><p><a href='/%s/'>Back to blog</a>.</p>", visitor.getName());
- }
- break;
- case "jid-del":
- // FIXME: stop using ugnich-csv in parameters
- String[] params = request.getParameter("delete").split(";", 2);
- boolean res = false;
- if (params[0].equals("xmpp")) {
- res = userService.deleteJID(visitor.getUid(), params[1]);
- } else if (params[0].equals("xmpp-unauth")) {
- res = userService.unauthJID(visitor.getUid(), params[1]);
- }
- if (res) {
- result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
- } else {
- result = "<p>Error</p>";
- }
- break;
- case "email-add":
- if (!emailService.verifyAddressByCode(visitor.getUid(), request.getParameter("account"))) {
- String authCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
- if (emailService.addVerificationCode(visitor.getUid(), request.getParameter("account"), authCode)) {
- Session session = Session.getDefaultInstance(System.getProperties());
- try {
- MimeMessage message = new MimeMessage(session);
- message.setFrom(new InternetAddress("noreply@mail.juick.com"));
- message.addRecipient(Message.RecipientType.TO, new InternetAddress(request.getParameter("account")));
- message.setSubject("Juick authorization link");
- message.setText(String.format("Follow link to attach this email to Juick account:\n" +
- "http://juick.com/settings?page=auth-email&code=%s\n\n" +
- "If you don't know, what this mean - just ignore this mail.\n", authCode));
- Transport.send(message);
- result = "<p>Authorization link has been sent to your email. Follow it to proceed.</p>" +
- "<p><a href=\"/settings\">Back</a></p>";
-
- } catch (MessagingException ex) {
- logger.error("mail exception", ex);
- throw new HttpBadRequestException();
- }
- }
- }
- break;
- case "email-del":
- if (emailService.deleteEmail(visitor.getUid(), request.getParameter("account"))) {
- result = "<p>Deleted. <a href=\"/settings\">Back</a>.</p>";
- } else {
- result = "<p>An error occured while deleting.</p>";
- }
- break;
- case "email-subscr":
- if (emailService.setNotificationsEmail(visitor.getUid(), request.getParameter("account"))) {
- result = String.format("<p>Saved! Will send notifications to <strong>%s</strong>." +
- "</p><p><a href=\"/settings\">Back</a></p>", request.getParameter("account"));
- } else {
- result = "<p>Disabled.</p><p><a href=\"/settings\">Back</a></p>";
- }
- break;
- case "twitter-del":
- crosspostService.deleteTwitterToken(visitor.getUid());
- for (Cookie cookie : request.getCookies()) {
- if (cookie.getName().equals("request_token")) {
- cookie.setMaxAge(0);
- response.addCookie(cookie);
- }
- if (cookie.getName().equals("request_token_secret")) {
- cookie.setMaxAge(0);
- response.addCookie(cookie);
- }
- }
- result = "<p><a href=\"/settings\">Back</a></p>";
- break;
- case "telegram-del":
- telegramService.deleteTelegramUser(visitor.getUid());
- result = "<p><a href=\"/settings\">Back</a></p>";
- break;
- case "facebook-disable":
- crosspostService.disableFBCrosspost(visitor.getUid());
- result = "<p><a href=\"/settings\">Back</a></p>";
- break;
- case "facebook-enable":
- crosspostService.enableFBCrosspost(visitor.getUid());
- result = "<p><a href=\"/settings\">Back</a></p>";
- break;
- case "vk-del":
- crosspostService.deleteVKUser(visitor.getUid());
- result = "<p><a href=\"/settings\">Back</a></p>";
- break;
- default:
- throw new HttpBadRequestException();
- }
-
- model.addAttribute("title", "Настройки");
- model.addAttribute("visitor", visitor);
- model.addAttribute("result", result);
- return "views/settings_result";
- }
- @PostMapping("/settings/unsubscribe")
- public String unsubscribeOneClick(@RequestParam(name = "List-Unsubscribe") String unsubscribe,
- ModelMap model) {
- User user = UserUtils.getCurrentUser();
- if (!user.isAnonymous()) {
- if (unsubscribe.equals("One-Click")) {
- emailService.setNotificationsEmail(user.getUid(), StringUtils.EMPTY);
- model.addAttribute("title", "Настройки");
- model.addAttribute("visitor", user);
- model.addAttribute("result", "Unsubscribed");
- return "views/settings_result";
- }
- }
- throw new HttpBadRequestException();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/SignUp.java b/juick-server/src/main/java/com/juick/server/www/controllers/SignUp.java
deleted file mode 100644
index 6a4fe063..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/SignUp.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.HttpForbiddenException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.CrosspostService;
-import com.juick.service.EmailService;
-import com.juick.service.MessengerService;
-import com.juick.service.UserService;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import javax.inject.Inject;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Controller
-public class SignUp {
-
- @Inject
- private UserService userService;
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private MessengerService messengerService;
- @Inject
- private EmailService emailService;
-
-
- @GetMapping("/signup")
- protected String doGet(@RequestParam String type, @RequestParam String hash, ModelMap model) {
- com.juick.User visitor = UserUtils.getCurrentUser();
-
- if (hash.length() > 36 || !type.matches("^[a-zA-Z0-9\\-]+$")
- || !hash.matches("^[a-zA-Z0-9\\-]+$")) {
- throw new HttpBadRequestException();
- }
-
- String account = null;
- switch (type) {
- case "fb":
- account = crosspostService.getFacebookNameByHash(hash);
- break;
- case "vk":
- account = crosspostService.getVKNameByHash(hash);
- break;
- case "xmpp":
- account = crosspostService.getJIDByHash(hash);
- break;
- case "durov":
- account = crosspostService.getTelegramNameByHash(hash);
- break;
- case "messenger":
- account = messengerService.getDisplayName(hash);
- break;
- case "email":
- account = emailService.getEmailByAuthCode(hash);
- }
- if (account == null) {
- throw new HttpBadRequestException();
- }
-
- model.addAttribute("title", "Новый пользователь");
- model.addAttribute("visitor", visitor);
- model.addAttribute("account", account);
- model.addAttribute("type", type);
- model.addAttribute("hash", hash);
- return "views/signup";
- }
-
- @PostMapping("/signup")
- protected String doPost(
- HttpServletResponse response,
- @RequestParam String type,
- @RequestParam String hash,
- @RequestParam String action,
- @RequestParam(required = false) String username,
- @RequestParam(required = false) String password) {
- com.juick.User visitor = UserUtils.getCurrentUser();
- int uid = 0;
-
- if (hash.length() > 36 || !type.matches("^[a-zA-Z0-9\\-]+$") || !hash.matches("^[a-zA-Z0-9\\-]+$")) {
- throw new HttpBadRequestException();
- }
-
- if (action.charAt(0) == 'l') {
-
- if (visitor.isAnonymous()) {
- if (username.length() > 32) {
- throw new HttpBadRequestException();
- }
- uid = userService.checkPassword(username, password);
- } else {
- uid = visitor.getUid();
- }
-
- if (uid <= 0) {
- throw new HttpForbiddenException();
- }
-
- if (!(type.charAt(0) == 'f' && crosspostService.setFacebookUser(hash, uid))
- && !(type.charAt(0) == 'v' && crosspostService.setVKUser(hash, uid))
- && !(type.charAt(0) == 'd' && crosspostService.setTelegramUser(hash, uid))
- && !(type.charAt(0) == 'x' && userService.getAllJIDs(visitor).size() > 0 && crosspostService.setJIDUser(hash, uid))
- && !(type.charAt(0) == 'm' && messengerService.linkMessengerUser(hash, uid))) {
- if (type.equals("email")) {
- String email = emailService.getEmailByAuthCode(hash);
- emailService.addEmail(uid, email);
- emailService.deleteAuthCode(hash);
- } else {
- throw new HttpBadRequestException();
- }
- }
-
- } else { // Create new account
- if (username.length() < 2 || username.length() > 16 || !username.matches("^[a-zA-Z0-9\\-]+$") || password.length() < 6 || password.length() > 32) {
- throw new HttpBadRequestException();
- }
-
- // CHECK USERNAME
-
- uid = userService.createUser(username, password);
- if (uid <= 0) {
- throw new HttpBadRequestException();
- }
-
- if (!(type.charAt(0) == 'f' && crosspostService.setFacebookUser(hash, uid))
- && !(type.charAt(0) == 'v' && crosspostService.setVKUser(hash, uid))
- && !(type.charAt(0) == 'd' && crosspostService.setTelegramUser(hash, uid))
- && !(type.charAt(0) == 'm' && messengerService.linkMessengerUser(hash, uid))) {
- if (type.equals("email")) {
- String email = emailService.getEmailByAuthCode(hash);
- emailService.addEmail(uid, email);
- emailService.deleteAuthCode(hash);
- } else {
- throw new HttpBadRequestException();
- }
- }
- }
-
- if (visitor.isAnonymous()) {
- hash = userService.getHashByUID(uid);
- Cookie c = new Cookie("hash", hash);
- c.setMaxAge(365 * 24 * 60 * 60);
- response.addCookie(c);
- }
- return "redirect:/";
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/www/controllers/SocialLogin.java b/juick-server/src/main/java/com/juick/server/www/controllers/SocialLogin.java
deleted file mode 100644
index bc631a1a..00000000
--- a/juick-server/src/main/java/com/juick/server/www/controllers/SocialLogin.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.www.controllers;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.scribejava.apis.FacebookApi;
-import com.github.scribejava.apis.TwitterApi;
-import com.github.scribejava.apis.VkontakteApi;
-import com.github.scribejava.core.builder.ServiceBuilder;
-import com.github.scribejava.core.model.*;
-import com.github.scribejava.core.oauth.OAuth10aService;
-import com.github.scribejava.core.oauth.OAuth20Service;
-import com.juick.model.facebook.User;
-import com.juick.server.Utils;
-import com.juick.server.util.HttpBadRequestException;
-import com.juick.server.util.UserUtils;
-import com.juick.service.CrosspostService;
-import com.juick.service.EmailService;
-import com.juick.service.TelegramService;
-import com.juick.service.UserService;
-import com.juick.model.vk.UsersResponse;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.codec.digest.HmacAlgorithms;
-import org.apache.commons.codec.digest.HmacUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.CookieValue;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
-
-/**
- *
- * @author Ugnich Anton
- */
-@Controller
-public class SocialLogin {
-
- private static final Logger logger = LoggerFactory.getLogger(SocialLogin.class);
-
- @Value("${facebook_appid:appid}")
- private String FACEBOOK_APPID;
- @Value("${facebook_secret:secret}")
- private String FACEBOOK_SECRET;
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- private String facebookRedirectUri;
- private static final String VK_REDIRECT = "http://juick.com/_vklogin";
- private static final String TWITTER_VERIFY_URL = "https://api.twitter.com/1.1/account/verify_credentials.json";
- @Inject
- private ObjectMapper jsonMapper;
- private ServiceBuilder facebookBuilder, twitterBuilder, vkBuilder;
-
- @Value("${twitter_consumer_key:appid}")
- private String twitterConsumerKey;
- @Value("${twitter_consumer_secret:secret}")
- private String twitterConsumerSecret;
- @Value("${vk_appid:appid}")
- private String VK_APPID;
- @Value("${vk_secret:secret}")
- private String VK_SECRET;
- @Value("${telegram_token:secret}")
- private String telegramToken;
-
- @Inject
- private CrosspostService crosspostService;
- @Inject
- private UserService userService;
- @Inject
- private EmailService emailService;
- @Inject
- private TelegramService telegramService;
-
- @PostConstruct
- public void init() {
- facebookBuilder = new ServiceBuilder(FACEBOOK_APPID);
- twitterBuilder = new ServiceBuilder(twitterConsumerKey);
- vkBuilder = new ServiceBuilder(VK_APPID);
- UriComponentsBuilder facebookRedirectBuilder = UriComponentsBuilder.fromUriString(baseUri);
- facebookRedirectUri = facebookRedirectBuilder.replacePath("/_fblogin").build().toUriString();
- }
-
- @GetMapping("/_fblogin")
- protected String doFacebookLogin(HttpServletRequest request,
- @RequestParam(required = false) String code,
- @RequestParam(required = false) String state,
- HttpServletResponse response) throws IOException, ExecutionException, InterruptedException {
- if (StringUtils.isBlank(code)) {
- String fbstate = UUID.randomUUID().toString();
- if (StringUtils.isBlank(state)) {
- state = Utils.getPreviousPageByRequest(request).orElse("https://juick.com/");
- }
- crosspostService.addFacebookState(fbstate, state);
- OAuth20Service facebookAuthService = facebookBuilder
- .apiSecret(FACEBOOK_SECRET)
- .callback(facebookRedirectUri)
- .scope("email")
- .state(fbstate)
- .build(FacebookApi.instance());
- return "redirect:" + facebookAuthService.getAuthorizationUrl();
- }
-
- String redirectUrl = crosspostService.verifyFacebookState(state);
- if (StringUtils.isEmpty(redirectUrl)) {
- logger.error("state is missing");
- throw new HttpBadRequestException();
- }
- OAuth20Service facebookService = facebookBuilder
- .apiKey(FACEBOOK_APPID)
- .apiSecret(FACEBOOK_SECRET)
- .callback(facebookRedirectUri)
- .scope("email")
- .state(state)
- .build(FacebookApi.instance());
- OAuth2AccessToken token = facebookService.getAccessToken(code);
- final OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://graph.facebook.com/v2.10/me?fields=id,name,link,verified,email");
- facebookService.signRequest(token, meRequest);
- String graph = facebookService.execute(meRequest).getBody();
- if (StringUtils.isBlank(graph)) {
- logger.error("FACEBOOK GRAPH ERROR");
- throw new HttpBadRequestException();
- }
- User fb = jsonMapper.readValue(graph, User.class);
- long fbID = NumberUtils.toLong(fb.getId(), 0);
- if (fbID == 0 || StringUtils.isBlank(fb.getName()) || StringUtils.isBlank(fb.getLink())) {
- logger.error("Missing required fields, id: {}, name: {}, link: {}", fbID, fb.getName(), fb.getLink());
- throw new HttpBadRequestException();
- }
-
- int uid = crosspostService.getUIDbyFBID(fbID);
- if (uid > 0) {
- if (!crosspostService.updateFacebookUser(fbID, token.getAccessToken(), fb.getName(), fb.getLink())) {
- logger.error("error updating facebook user, id: {}, token: {}", fbID, token.getAccessToken());
- throw new HttpBadRequestException();
- }
- Cookie c = new Cookie("hash", userService.getHashByUID(uid));
- c.setMaxAge(50 * 24 * 60 * 60);
- response.addCookie(c);
- return "redirect:" + redirectUrl;
- } else if (fb.getVerified()) {
- if (!crosspostService.createFacebookUser(fbID, state, token.getAccessToken(), fb.getName(), fb.getLink())) {
- if (StringUtils.isNotEmpty(fb.getEmail())) {
- logger.info("found {} for facebook user {}", fb.getEmail(), fb.getLink());
- Integer userId = crosspostService.getUIDbyFBID(fbID);
- if (!emailService.getEmails(userId, false).contains(fb.getEmail())) {
- emailService.addEmail(userId, fb.getEmail());
- }
- }
- logger.info("email not found for facebook user {}", fb.getLink());
- throw new HttpBadRequestException();
- }
- return "redirect:/signup?type=fb&hash=" + state;
- } else {
- logger.error("Facebook account is not verified, id: {}", fbID);
- throw new HttpBadRequestException();
- }
- }
- @GetMapping("/_twitter")
- protected void doTwitterLogin(HttpServletRequest request, HttpServletResponse response)
- throws IOException, ExecutionException, InterruptedException {
- String hash = StringUtils.EMPTY, request_token = StringUtils.EMPTY, request_token_secret = StringUtils.EMPTY;
- String verifier = request.getParameter("oauth_verifier");
- Cookie[] cookies = request.getCookies();
- for (Cookie cookie : cookies) {
- if (cookie.getName().equals("hash")) {
- hash = cookie.getValue();
- }
- if (cookie.getName().equals("request_token")) {
- request_token = cookie.getValue();
- }
- if (cookie.getName().equals("request_token_secret")) {
- request_token_secret = cookie.getValue();
- }
- }
- com.juick.User user = UserUtils.getCurrentUser();
- OAuth10aService oAuthService = twitterBuilder
- .apiSecret(twitterConsumerSecret)
- .callback("https://juick.com/_twitter")
- .build(TwitterApi.instance());
-
- if (request_token.isEmpty() && request_token_secret.isEmpty()
- && (verifier == null || verifier.isEmpty())) {
- OAuth1RequestToken requestToken = oAuthService.getRequestToken();
- String authUrl = oAuthService.getAuthorizationUrl(requestToken);
- response.addCookie(new Cookie("request_token", requestToken.getToken()));
- response.addCookie(new Cookie("request_token_secret", requestToken.getTokenSecret()));
- response.setStatus(HttpServletResponse.SC_FOUND);
- response.setHeader("Location", authUrl);
- } else {
- if (verifier != null && verifier.length() > 0) {
- OAuth1RequestToken requestToken = new OAuth1RequestToken(request_token, request_token_secret);
- OAuth1AccessToken accessToken = oAuthService.getAccessToken(requestToken, verifier);
- OAuthRequest oAuthRequest = new OAuthRequest(Verb.GET, TWITTER_VERIFY_URL);
- oAuthService.signRequest(accessToken, oAuthRequest);
- com.juick.model.twitter.User twitterUser = jsonMapper.readValue(oAuthService.execute(oAuthRequest).getBody(),
- com.juick.model.twitter.User.class);
- if (userService.linkTwitterAccount(user, accessToken.getToken(), accessToken.getTokenSecret(),
- twitterUser.getScreenName())) {
- response.setStatus(HttpServletResponse.SC_FOUND);
- response.setHeader("Location", "http://juick.com/settings");
- } else {
- response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- }
- }
- }
- }
- @GetMapping("/_vklogin")
- protected String doVKLogin(HttpServletRequest request,
- @RequestParam(required = false) String code,
- @RequestParam(required = false) String state,
- @CookieValue(required = false) String vkstate,
- HttpServletResponse response) throws IOException, ExecutionException, InterruptedException {
- if (StringUtils.isBlank(code)) {
- vkstate = UUID.randomUUID().toString();
- Cookie c = new Cookie("vkstate", vkstate);
- response.addCookie(c);
- OAuth20Service vkAuthService = vkBuilder
- .apiSecret(VK_SECRET)
- .scope("friends,wall,offline")
- .state(vkstate)
- .callback(VK_REDIRECT)
- .build(VkontakteApi.instance());
- return "redirect:" + vkAuthService.getAuthorizationUrl();
- }
-
- if (StringUtils.isBlank(vkstate) || !vkstate.equals(state)) {
- throw new HttpBadRequestException();
- } else {
- Cookie c = new Cookie("vkstate", "-");
- c.setMaxAge(0);
- response.addCookie(c);
- }
-
- OAuth20Service vkService = vkBuilder
- .apiKey(VK_APPID)
- .apiSecret(VK_SECRET)
- .build(VkontakteApi.instance());
- OAuth2AccessToken token = vkService.getAccessToken(code);
-
- OAuthRequest meRequest = new OAuthRequest(Verb.GET, "https://api.vk.com/method/users.get?fields=screen_name&v=5.73");
- vkService.signRequest(token, meRequest);
- String graph = vkService.execute(meRequest).getBody();
-
- com.juick.model.vk.User jsonUser = jsonMapper.readValue(graph, UsersResponse.class).getUsers().get(0);
- String vkName = jsonUser.getFirstName() + " " + jsonUser.getLastName();
- String vkLink = jsonUser.getScreenName();
-
- if (vkName.length() == 1 || StringUtils.isBlank(vkLink)) {
- logger.error("vk user error");
- throw new HttpBadRequestException();
- }
-
- Long vkID = NumberUtils.toLong(jsonUser.getId(), 0);
- int uid = crosspostService.getUIDbyVKID(vkID);
- if (uid > 0) {
- Cookie c = new Cookie("hash", userService.getHashByUID(uid));
- c.setMaxAge(50 * 24 * 60 * 60);
- response.addCookie(c);
- return "redirect:/" + Utils.getPreviousPageByRequest(request).orElse(StringUtils.EMPTY);
- } else {
- String loginhash = UUID.randomUUID().toString();
- if (!crosspostService.createVKUser(vkID, loginhash, token.getAccessToken(), vkName, vkLink)) {
- logger.error("create vk user error");
- throw new HttpBadRequestException();
- }
- return "redirect:/signup?type=vk&hash=" + loginhash;
- }
- }
-
- @GetMapping("/_tglogin")
- public String doDurovLogin(HttpServletRequest request,
- @RequestParam Map<String, String> params,
- HttpServletResponse response) {
- String dataCheckString = params.entrySet().stream()
- .filter(p -> !p.getKey().equals("hash"))
- .sorted(Map.Entry.comparingByKey())
- .map(p -> p.getKey() + "=" + p.getValue())
- .collect(Collectors.joining("\n"));
- String hash = params.get("hash");
- byte[] secretKey = DigestUtils.sha256(telegramToken);
- String resultString = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secretKey).hmacHex(dataCheckString);
- if (hash.equals(resultString)) {
- Long tgUser = Long.valueOf(params.get("id"));
- int uid = telegramService.getUser(tgUser);
- if (uid > 0) {
- Cookie c = new Cookie("hash", userService.getHashByUID(uid));
- c.setMaxAge(50 * 24 * 60 * 60);
- response.addCookie(c);
- return "redirect:/" + Utils.getPreviousPageByRequest(request).orElse(StringUtils.EMPTY);
- } else {
- String username = StringUtils.defaultString(params.get("username"), params.get("first_name"));
- telegramService.createTelegramUser(tgUser, username);
- return "redirect:/signup?type=durov&hash=" + userService.getSignUpHashByTelegramID(tgUser, username);
- }
- } else {
- logger.warn("invalid tg hash {} for {}", resultString, hash);
- }
- throw new HttpBadRequestException();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java b/juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java
deleted file mode 100644
index e9a9707e..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/JidConverter.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.juick.server.xmpp;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.lang.Nullable;
-import rocks.xmpp.addr.Jid;
-
-public class JidConverter implements Converter<String, Jid> {
- @Nullable
- @Override
- public Jid convert(String jidStr) {
- return Jid.of(jidStr);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java b/juick-server/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java
deleted file mode 100644
index 231696ec..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/XMPPStatusPage.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.juick.server.xmpp;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.helpers.XMPPStatus;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RestController;
-import rocks.xmpp.addr.Jid;
-import springfox.documentation.annotations.ApiIgnore;
-
-import javax.inject.Inject;
-import java.util.stream.Collectors;
-
-@RestController
-@ConditionalOnProperty("xmppbot_jid")
-public class XMPPStatusPage {
- @Inject
- private XMPPServer xmpp;
- @ApiIgnore
- @RequestMapping(method = RequestMethod.GET, value = "/api/xmpp-status", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
- public XMPPStatus xmppStatus() {
- XMPPStatus status = new XMPPStatus();
- if (xmpp != null) {
- status.setInbound(xmpp.getInConnections().stream().map(c -> c.from).flatMap(j -> j.stream().map(Jid::getDomain)).collect(Collectors.toList()));
- status.setOutbound(xmpp.getOutConnections().keySet().stream()
- .map(c -> c.to).map(Jid::getDomain).collect(Collectors.toList()));
- }
- return status;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java b/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
deleted file mode 100644
index 99d89866..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/helpers/XMPPStatus.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.helpers;
-
-import com.juick.server.xmpp.s2s.ConnectionIn;
-import com.juick.server.xmpp.s2s.ConnectionOut;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Created by vitalyster on 16.02.2017.
- */
-public class XMPPStatus {
- private List<String> inbound;
- private List<String> outbound;
-
- public List<String> getInbound() {
- return inbound;
- }
-
- public void setInbound(List<String> inbound) {
- this.inbound = inbound;
- }
-
- public List<String> getOutbound() {
- return outbound;
- }
-
- public void setOutbound(List<String> outbound) {
- this.outbound = outbound;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java b/juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java
deleted file mode 100644
index 7500cbf8..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/iq/MessageQuery.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.juick.server.xmpp.iq;
-
-import javax.xml.bind.annotation.XmlRootElement;
-
-@XmlRootElement(name = "query")
-public class MessageQuery {
- private MessageQuery() {
-
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java b/juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java
deleted file mode 100644
index dada8289..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/iq/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-@XmlAccessorType(XmlAccessType.FIELD)
-@XmlSchema(namespace = "http://juick.com/query#messages", elementFormDefault = XmlNsForm.QUALIFIED)
-package com.juick.server.xmpp.iq;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlNsForm;
-import javax.xml.bind.annotation.XmlSchema; \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/Handshake.java b/juick-server/src/main/java/com/juick/server/xmpp/router/Handshake.java
deleted file mode 100644
index 0bc501dd..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/Handshake.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * Created by vitalyster on 30.01.2017.
- */
-public class Handshake {
- private String value;
-
- public static Handshake parse(XmlPullParser parser) throws IOException, XmlPullParserException {
- parser.next();
- Handshake handshake = new Handshake();
- handshake.setValue(XmlUtils.getTagText(parser));
- return handshake;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder("<handshake");
- if (getValue() != null) {
- str.append(">").append(getValue()).append("</handshake>");
- } else {
- str.append("/>");
- }
- return str.toString();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java b/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java
deleted file mode 100644
index 2154edf6..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/Stream.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author Ugnich Anton
- */
-public abstract class Stream {
-
- public boolean isLoggedIn() {
- return loggedIn;
- }
-
- public void setLoggedIn(boolean loggedIn) {
- this.loggedIn = loggedIn;
- }
-
- public Jid from;
- public Jid to;
- private InputStream is;
- private OutputStream os;
- private XmlPullParserFactory factory;
- protected XmlPullParser parser;
- private OutputStreamWriter writer;
- StreamHandler streamHandler;
- private boolean loggedIn;
- private Instant created;
- private Instant updated;
- String streamId;
- private boolean secured;
-
- public Stream(final Jid from, final Jid to, final InputStream is, final OutputStream os) throws XmlPullParserException {
- this.from = from;
- this.to = to;
- this.is = is;
- this.os = os;
- factory = XmlPullParserFactory.newInstance();
- created = updated = Instant.now();
- streamId = UUID.randomUUID().toString();
- }
-
- public void restartStream() throws XmlPullParserException {
- parser = factory.newPullParser();
- parser.setInput(new InputStreamReader(is, StandardCharsets.UTF_8));
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
- }
-
- public void connect() {
- try {
- restartStream();
- handshake();
- parse();
- } catch (XmlPullParserException e) {
- StreamError invalidXmlError = new StreamError("invalid-xml");
- send(invalidXmlError.toString());
- connectionFailed(new Exception(invalidXmlError.getCondition()));
- } catch (IOException e) {
- connectionFailed(e);
- }
- }
-
- public void setHandler(final StreamHandler streamHandler) {
- this.streamHandler = streamHandler;
- }
-
- public abstract void handshake() throws XmlPullParserException, IOException;
-
- public void logoff() {
- setLoggedIn(false);
- try {
- writer.flush();
- writer.close();
- //TODO close parser
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- public void send(final String str) {
- try {
- updated = Instant.now();
- writer.write(str);
- writer.flush();
- } catch (final Exception e) {
- connectionFailed(e);
- }
- }
-
- private void parse() throws IOException, XmlPullParserException {
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() == XmlPullParser.IGNORABLE_WHITESPACE) {
- setUpdated();
- }
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- setUpdated();
- final String tag = parser.getName();
- switch (tag) {
- case "message":
- case "presence":
- case "iq":
- streamHandler.stanzaReceived(XmlUtils.parseToString(parser, false));
- break;
- case "error":
- StreamError error = StreamError.parse(parser);
- connectionFailed(new Exception(error.getCondition()));
- return;
- default:
- XmlUtils.skip(parser);
- break;
- }
- }
- }
-
- /**
- * This method is used to be called on a parser or a connection error.
- * It tries to close the XML-Reader and XML-Writer one last time.
- */
- private void connectionFailed(final Exception ex) {
- if (isLoggedIn()) {
- try {
- writer.close();
- //TODO close parser
- } catch (Exception e) {
- }
- }
- if (streamHandler != null) {
- streamHandler.fail(ex);
- }
- }
-
- public Instant getCreated() {
- return created;
- }
-
- public Instant getUpdated() {
- return updated;
- }
- public String getStreamId() {
- return streamId;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void setUpdated() {
- this.updated = Instant.now();
- }
-
- public InputStream getInputStream() {
- return is;
- }
-
- public void setInputStream(InputStream is) {
- this.is = is;
- }
-
- public OutputStream getOutputStream() {
- return os;
- }
-
- public void setOutputStream(OutputStream os) {
- this.os = os;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
deleted file mode 100644
index a58adfc5..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamComponentServer.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.UUID;
-
-/**
- * Created by vitalyster on 30.01.2017.
- */
-public class StreamComponentServer extends Stream {
-
- private String streamId, secret;
-
- public String getStreamId() {
- return streamId;
- }
-
-
- public StreamComponentServer(InputStream is, OutputStream os, String password) throws XmlPullParserException {
- super(null, null, is, os);
- secret = password;
- streamId = UUID.randomUUID().toString();
- }
- @Override
- public void handshake() throws XmlPullParserException, IOException {
- parser.next();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace(null).equals(StreamNamespaces.NS_COMPONENT_ACCEPT)
- || !parser.getNamespace("stream").equals(StreamNamespaces.NS_STREAM)) {
- throw new IOException("invalid stream");
- }
- Jid domain = Jid.of(parser.getAttributeValue(null, "to"));
- if (streamHandler.filter(null, domain)) {
- send(new XMPPError(XMPPError.Type.cancel, "forbidden").toString());
- throw new IOException("invalid domain");
- }
- from = domain;
- to = domain;
- send(String.format("<stream:stream xmlns:stream='%s' " +
- "xmlns='%s' from='%s' id='%s'>", StreamNamespaces.NS_STREAM, StreamNamespaces.NS_COMPONENT_ACCEPT, from.asBareJid().toEscapedString(), streamId));
- Handshake handshake = Handshake.parse(parser);
- boolean authenticated = handshake.getValue().equals(DigestUtils.sha1Hex(streamId + secret));
- setLoggedIn(authenticated);
- if (!authenticated) {
- send(new XMPPError(XMPPError.Type.cancel, "not-authorized").toString());
- streamHandler.fail(new IOException("stream:stream, failed authentication"));
- return;
- }
- send(new Handshake().toString());
- streamHandler.ready(this);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java
deleted file mode 100644
index f731f039..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamError.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-
-/**
- * Created by vitalyster on 03.02.2017.
- */
-public class StreamError {
-
- private String condition;
- private String text;
-
- public StreamError() {}
-
- public StreamError(String condition) {
- this.condition = condition;
- }
-
- public static StreamError parse(XmlPullParser parser) throws IOException, XmlPullParserException {
- StreamError streamError = new StreamError();
- final int initial = parser.getDepth();
- while (true) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initial + 1) {
- final String tag = parser.getName();
- final String xmlns = parser.getNamespace();
- if (tag.equals("text") && xmlns.equals(StreamNamespaces.NS_XMPP_STREAMS)) {
- streamError.text = XmlUtils.getTagText(parser);
- } else if (xmlns.equals(StreamNamespaces.NS_XMPP_STREAMS)) {
- streamError.condition = tag;
- } else {
- XmlUtils.skip(parser);
- }
- } else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initial) {
- break;
- }
- }
- return streamError;
- }
-
- public String getCondition() {
- return condition;
- }
-
- @Override
- public String toString() {
- return String.format("<stream:error><%s xmlns='%s'/></stream:error>", condition, StreamNamespaces.NS_XMPP_STREAMS);
- }
-
- public String getText() {
- return text;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java
deleted file mode 100644
index e8fc324f..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamFeatures.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2013, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import java.io.IOException;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class StreamFeatures {
-
- public static final int NOTAVAILABLE = -1;
- public static final int AVAILABLE = 0;
- public static final int REQUIRED = 1;
- public int STARTTLS = NOTAVAILABLE;
- public int ZLIB = NOTAVAILABLE;
- public int PLAIN = NOTAVAILABLE;
- public int DIGEST_MD5 = NOTAVAILABLE;
- public int REGISTER = NOTAVAILABLE;
- public int EXTERNAL = NOTAVAILABLE;
-
- public static StreamFeatures parse(final XmlPullParser parser) throws XmlPullParserException, IOException {
- StreamFeatures features = new StreamFeatures();
- final int initial = parser.getDepth();
- while (true) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG && parser.getDepth() == initial + 1) {
- final String tag = parser.getName();
- final String xmlns = parser.getNamespace();
- if (tag.equals("starttls") && xmlns != null && xmlns.equals("urn:ietf:params:xml:ns:xmpp-tls")) {
- features.STARTTLS = AVAILABLE;
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("required")) {
- features.STARTTLS = REQUIRED;
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("compression") && xmlns != null && xmlns.equals("http://jabber.org/features/compress")) {
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("method")) {
- final String method = XmlUtils.getTagText(parser).toUpperCase();
- if (method.equals("ZLIB")) {
- features.ZLIB = AVAILABLE;
- }
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("mechanisms") && xmlns != null && xmlns.equals("urn:ietf:params:xml:ns:xmpp-sasl")) {
- while (parser.next() == XmlPullParser.START_TAG) {
- if (parser.getName().equals("mechanism")) {
- final String mechanism = XmlUtils.getTagText(parser).toUpperCase();
- if (mechanism.equals("PLAIN")) {
- features.PLAIN = AVAILABLE;
- } else if (mechanism.equals("DIGEST-MD5")) {
- features.DIGEST_MD5 = AVAILABLE;
- } else if (mechanism.equals("EXTERNAL")) {
- features.EXTERNAL = AVAILABLE;
- }
- } else {
- XmlUtils.skip(parser);
- }
- }
- } else if (tag.equals("register") && xmlns != null && xmlns.equals("http://jabber.org/features/iq-register")) {
- features.REGISTER = AVAILABLE;
- XmlUtils.skip(parser);
- } else {
- XmlUtils.skip(parser);
- }
- } else if (eventType == XmlPullParser.END_TAG && parser.getDepth() == initial) {
- break;
- }
- }
- return features;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
deleted file mode 100644
index 048c61ec..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamHandler.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 01.02.2017.
- */
-public interface StreamHandler {
- void ready(StreamComponentServer componentServer);
- void fail(final Exception ex);
- boolean filter(Jid from, Jid to);
- void stanzaReceived(String stanza);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java b/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
deleted file mode 100644
index 1b9b1965..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/StreamNamespaces.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.juick.server.xmpp.router;
-
-public class StreamNamespaces {
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_SERVER = "jabber:server";
- public static final String NS_COMPONENT_ACCEPT = "jabber:component:accept";
- public static final String NS_XMPP_STREAMS = "urn:ietf:params:xml:ns:xmpp-streams";
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java
deleted file mode 100644
index 0cf9a3bc..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPError.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2013, ugnich
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import org.apache.commons.text.StringEscapeUtils;
-
-/**
- *
- * @author ugnich
- */
-public class XMPPError {
-
- public static final class Type {
-
- public static final String auth = "auth";
- public static final String cancel = "cancel";
- public static final String continue_ = "continue";
- public static final String modify = "modify";
- public static final String wait = "wait";
- }
- private final static String TagName = "error";
- public String by = null;
- private String type;
- private String condition;
- private String text = null;
-
- public XMPPError(String type, String condition) {
- this.type = type;
- this.condition = condition;
- }
-
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder("<").append(TagName).append("");
- if (by != null) {
- str.append(" by=\"").append(StringEscapeUtils.escapeXml10(by)).append("\"");
- }
- if (type != null) {
- str.append(" type=\"").append(StringEscapeUtils.escapeXml10(type)).append("\"");
- }
-
- if (condition != null) {
- str.append(">");
- str.append("<").append(StringEscapeUtils.escapeXml10(condition)).append(" xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"");
- if (text != null) {
- str.append(">").append(StringEscapeUtils.escapeXml10(text)).append("</").append(StringEscapeUtils.escapeXml10(condition))
- .append(">");
- } else {
- str.append("/>");
- }
- str.append("</").append(TagName).append(">");
- } else {
- str.append("/>");
- }
-
- return str.toString();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
deleted file mode 100644
index 6d67fa9c..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XMPPRouter.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.juick.server.xmpp.router;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.s2s.BasicXmppSession;
-import com.juick.server.xmpp.s2s.CacheEntry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.stanza.model.IQ;
-import rocks.xmpp.core.stanza.model.Message;
-import rocks.xmpp.core.stanza.model.Presence;
-import rocks.xmpp.core.stanza.model.Stanza;
-import rocks.xmpp.core.stanza.model.server.ServerIQ;
-import rocks.xmpp.core.stanza.model.server.ServerMessage;
-import rocks.xmpp.core.stanza.model.server.ServerPresence;
-import rocks.xmpp.util.XmppUtils;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-
-public class XMPPRouter implements StreamHandler {
- private static final Logger logger = LoggerFactory.getLogger("com.juick.server.xmpp");
-
- @Inject
- private ExecutorService service;
-
- private final List<StreamComponentServer> connections = Collections.synchronizedList(new ArrayList<>());
- private final List<CacheEntry> outCache = new CopyOnWriteArrayList<>();
-
- private ServerSocket listener;
-
- @Inject
- private BasicXmppSession session;
-
- @Value("${router_port:5347}")
- private int routerPort;
-
- @Inject
- private XMPPServer xmppServer;
-
- @PostConstruct
- public void init() {
- logger.info("component router initialized");
- service.submit(() -> {
- try {
- listener = new ServerSocket(routerPort);
- logger.info("component router listening on {}", routerPort);
- while (!listener.isClosed()) {
- if (Thread.currentThread().isInterrupted()) break;
- Socket socket = listener.accept();
- service.submit(() -> {
- try {
- StreamComponentServer client = new StreamComponentServer(socket.getInputStream(), socket.getOutputStream(), "secret");
- addConnectionIn(client);
- client.setHandler(this);
- client.connect();
- } catch (IOException e) {
- logger.error("component error", e);
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- }
- });
- }
- } catch (SocketException e) {
- // shutdown
- } catch (IOException e) {
- logger.warn("io exception", e);
- }
- });
- }
-
- @PreDestroy
- public void close() throws Exception {
- if (!listener.isClosed()) {
- listener.close();
- }
- synchronized (getConnections()) {
- for (Iterator<StreamComponentServer> i = getConnections().iterator(); i.hasNext(); ) {
- StreamComponentServer c = i.next();
- c.logoff();
- i.remove();
- }
- }
- service.shutdown();
- logger.info("XMPP router destroyed");
- }
-
- private void addConnectionIn(StreamComponentServer c) {
- synchronized (getConnections()) {
- getConnections().add(c);
- }
- }
-
- private void sendOut(Stanza s) {
- try {
- StringWriter stanzaWriter = new StringWriter();
- XMLStreamWriter xmppStreamWriter = XmppUtils.createXmppStreamWriter(
- session.getConfiguration().getXmlOutputFactory().createXMLStreamWriter(stanzaWriter));
- session.createMarshaller().marshal(s, xmppStreamWriter);
- xmppStreamWriter.flush();
- xmppStreamWriter.close();
- String xml = stanzaWriter.toString();
- logger.info("XMPPRouter (out): {}", xml);
- sendOut(s.getTo().getDomain(), xml);
- } catch (XMLStreamException | JAXBException e1) {
- logger.info("jaxb exception", e1);
- }
- }
-
- private void sendOut(String hostname, String xml) {
- boolean haveAnyConn = false;
-
- StreamComponentServer connOut = null;
- synchronized (getConnections()) {
- for (StreamComponentServer c : getConnections()) {
- if (c.to != null && c.to.getDomain().equals(hostname)) {
- if (c.isLoggedIn()) {
- connOut = c;
- break;
- } else {
- logger.info("bouncing stanza to {} component until it will be ready", hostname);
- boolean haveCache = false;
- for (CacheEntry entry : outCache) {
- if (entry.hostname != null && entry.hostname.equals(hostname)) {
- entry.xml += xml;
- entry.updated = Instant.now();
- haveCache = true;
- break;
- }
- }
- if (!haveCache) {
- outCache.add(new CacheEntry(Jid.of(hostname), xml));
- }
- }
- }
- }
- }
- if (connOut != null) {
- connOut.send(xml);
- return;
- }
- xmppServer.sendOut(Jid.of(hostname), xml);
-
- }
-
- public List<StreamComponentServer> getConnections() {
- return connections;
- }
-
- private Stanza parse(String xml) {
- try {
- Unmarshaller unmarshaller = session.createUnmarshaller();
- return (Stanza)unmarshaller.unmarshal(new StringReader(xml));
- } catch (JAXBException e) {
- logger.error("JAXB exception", e);
- }
- return null;
- }
- @Override
- public void stanzaReceived(String stanza) {
- Stanza input = parse(stanza);
- if (input instanceof Message) {
- sendOut(ServerMessage.from((Message)input));
- } else if (input instanceof IQ) {
- sendOut(ServerIQ.from((IQ)input));
- } else {
- sendOut(ServerPresence.from((Presence) input));
- }
- }
-
- public String getFromCache(Jid to) {
- final String[] cache = new String[1];
- outCache.stream().filter(c -> c.hostname != null && c.hostname.equals(to)).findFirst().ifPresent(c -> {
- cache[0] = c.xml;
- outCache.remove(c);
- });
- return cache[0];
- }
-
- @Override
- public void ready(StreamComponentServer componentServer) {
- logger.info("component {} ready", componentServer.to);
- String cache = getFromCache(componentServer.to);
- if (cache != null) {
- logger.debug("sending cache to {}", componentServer.to);
- componentServer.send(cache);
- }
- }
-
- @Override
- public void fail(Exception e) {
-
- }
-
- @Override
- public boolean filter(Jid jid, Jid jid1) {
- return false;
- }
-} \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
deleted file mode 100644
index 7579489f..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/router/XmlUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Juick
- * Copyright (C) 2008-2011, Ugnich Anton
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.juick.server.xmpp.router;
-
-import java.io.IOException;
-
-import org.apache.commons.text.StringEscapeUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-/**
- *
- * @author Ugnich Anton
- */
-public class XmlUtils {
-
- public static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- while (parser.getName() != null && !(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- }
- }
-
- public static String getTagText(XmlPullParser parser) throws XmlPullParserException, IOException {
- String ret = "";
- String tag = parser.getName();
-
- if (parser.next() == XmlPullParser.TEXT) {
- ret = parser.getText();
- }
-
- while (!(parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- parser.next();
- }
-
- return ret;
- }
-
- public static String parseToString(XmlPullParser parser, boolean skipXMLNS) throws XmlPullParserException, IOException {
- String tag = parser.getName();
- StringBuilder ret = new StringBuilder("<").append(tag);
-
- // skipXMLNS for xmlns="jabber:client"
-
- String ns = parser.getNamespace();
- if (!skipXMLNS && ns != null && !ns.isEmpty()) {
- ret.append(" xmlns=\"").append(ns).append("\"");
- }
-
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- String attr = parser.getAttributeName(i);
- if ((!skipXMLNS || !attr.equals("xmlns")) && !attr.contains(":")) {
- ret.append(" ").append(attr).append("=\"").append(StringEscapeUtils.escapeXml10(parser.getAttributeValue(i))).append("\"");
- }
- }
- ret.append(">");
-
- while (!(parser.next() == XmlPullParser.END_TAG && parser.getName().equals(tag))) {
- int event = parser.getEventType();
- if (event == XmlPullParser.START_TAG) {
- if (!parser.getName().contains(":")) {
- ret.append(parseToString(parser, false));
- } else {
- skip(parser);
- }
- } else if (event == XmlPullParser.TEXT) {
- ret.append(StringEscapeUtils.escapeXml10(parser.getText()));
- }
- }
-
- ret.append("</").append(tag).append(">");
- return ret.toString();
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java
deleted file mode 100644
index ae28f827..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/BasicXmppSession.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import rocks.xmpp.addr.Jid;
-import rocks.xmpp.core.XmppException;
-import rocks.xmpp.core.session.XmppSession;
-import rocks.xmpp.core.session.XmppSessionConfiguration;
-import rocks.xmpp.core.stanza.model.IQ;
-import rocks.xmpp.core.stanza.model.Message;
-import rocks.xmpp.core.stanza.model.Presence;
-import rocks.xmpp.core.stanza.model.server.ServerIQ;
-import rocks.xmpp.core.stanza.model.server.ServerMessage;
-import rocks.xmpp.core.stanza.model.server.ServerPresence;
-import rocks.xmpp.core.stream.model.StreamElement;
-
-/**
- * Created by vitalyster on 06.02.2017.
- */
-public class BasicXmppSession extends XmppSession {
- protected BasicXmppSession(String xmppServiceDomain, XmppSessionConfiguration configuration) {
- super(xmppServiceDomain, configuration);
- }
-
- public static BasicXmppSession create(String xmppServiceDomain, XmppSessionConfiguration configuration) {
- BasicXmppSession session = new BasicXmppSession(xmppServiceDomain, configuration);
- notifyCreationListeners(session);
- return session;
- }
-
- @Override
- public void connect(Jid from) throws XmppException {
-
- }
-
- @Override
- public Jid getConnectedResource() {
- return null;
- }
-
- @Override
- protected StreamElement prepareElement(StreamElement element) {
- if (element instanceof Message) {
- element = ServerMessage.from((Message) element);
- } else if (element instanceof Presence) {
- element = ServerPresence.from((Presence) element);
- } else if (element instanceof IQ) {
- element = ServerIQ.from((IQ) element);
- }
-
- return element;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
deleted file mode 100644
index 33e875bd..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/CacheEntry.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import rocks.xmpp.addr.Jid;
-
-import java.time.Instant;
-
-/**
- *
- * @author ugnich
- */
-public class CacheEntry {
-
- public Jid hostname;
- public Instant created;
- public Instant updated;
- public String xml;
-
- public CacheEntry(Jid hostname, String xml) {
- this.hostname = hostname;
- this.created = this.updated =Instant.now();
- this.xml = xml;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java
deleted file mode 100644
index 4fa8e741..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/Connection.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.juick.server.XMPPServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.time.Instant;
-import java.util.UUID;
-
-/**
- *
- * @author ugnich
- */
-public class Connection {
-
- protected static final Logger logger = LoggerFactory.getLogger(Connection.class);
-
- public String streamID;
- public Instant created;
- public Instant updated;
- public long bytesLocal = 0;
- public long packetsLocal = 0;
- XMPPServer xmpp;
- private Socket socket;
- public static final String NS_DB = "jabber:server:dialback";
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_SASL = "urn:ietf:params:xml:ns:xmpp-sasl";
- public static final String NS_STREAM = "http://etherx.jabber.org/streams";
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- XmlPullParser parser = factory.newPullParser();
- OutputStreamWriter writer;
- private boolean secured = false;
- private boolean authenticated = false;
- private boolean trusted = false;
-
-
-
- public Connection(XMPPServer xmpp) throws XmlPullParserException {
- this.xmpp = xmpp;
- created = updated = Instant.now();
- }
-
- public void logParser() {
- if (streamID == null) {
- return;
- }
- String tag = "IN: <" + parser.getName();
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- tag += " " + parser.getAttributeName(i) + "=\"" + parser.getAttributeValue(i) + "\"";
- }
- tag += ">...</" + parser.getName() + ">\n";
- logger.trace(tag);
- }
-
- public void sendStanza(String xml) {
- if (streamID != null) {
- logger.trace("OUT: {}\n", xml);
- }
- try {
- writer.write(xml);
- writer.flush();
- } catch (IOException e) {
- logger.error("send stanza failed", e);
- }
-
- updated = Instant.now();
- bytesLocal += xml.length();
- packetsLocal++;
- }
-
- public void closeConnection() {
- if (streamID != null) {
- logger.debug("closing stream {}", streamID);
- }
-
- try {
- writer.write("</stream:stream>");
- } catch (Exception e) {
- }
-
- try {
- writer.close();
- } catch (Exception e) {
- }
-
- try {
- socket.close();
- } catch (Exception e) {
- }
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public void restartParser() throws XmlPullParserException, IOException {
- streamID = UUID.randomUUID().toString();
- parser = factory.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new InputStreamReader(socket.getInputStream()));
- writer = new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8);
- }
-
- @JsonIgnore
- public Socket getSocket() {
- return socket;
- }
-
- public void setSocket(Socket socket) {
- this.socket = socket;
- }
-
- public boolean isAuthenticated() {
- return authenticated;
- }
-
- public void setAuthenticated(boolean authenticated) {
- this.authenticated = authenticated;
- }
-
- public boolean isTrusted() {
- return trusted;
- }
-
- public void setTrusted(boolean trusted) {
- this.trusted = trusted;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
deleted file mode 100644
index 72c3ba8d..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionIn.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.XMPPServer;
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.router.XmlUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.SocketException;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.stream.Collectors;
-
-/**
- * @author ugnich
- */
-public class ConnectionIn extends Connection implements Runnable {
-
- final public List<Jid> from = new CopyOnWriteArrayList<>();
- public Instant received;
- public long packetsRemote = 0;
- ConnectionListener listener;
-
- public ConnectionIn(XMPPServer xmpp, Socket socket) throws XmlPullParserException, IOException {
- super(xmpp);
- this.setSocket(socket);
- restartParser();
- }
-
- @Override
- public void run() {
- try {
- parser.next(); // stream:stream
- updateTsRemoteData();
- if (!parser.getName().equals("stream")
- || !parser.getNamespace("stream").equals(NS_STREAM)) {
-// || !parser.getAttributeValue(null, "version").equals("1.0")
-// || !parser.getAttributeValue(null, "to").equals(Main.HOSTNAME)) {
- throw new Exception(String.format("stream from %s invalid", getSocket().getRemoteSocketAddress()));
- }
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null) {
- streamID = UUID.randomUUID().toString();
- }
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- String from = parser.getAttributeValue(null, "from");
-
- if (Arrays.asList(xmpp.bannedHosts).contains(from)) {
- closeConnection();
- return;
- }
- sendOpenStream(from, xmppversionnew);
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- updateTsRemoteData();
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
- logParser();
-
- packetsRemote++;
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String dfrom = parser.getAttributeValue(null, "from");
- String to = parser.getAttributeValue(null, "to");
- logger.debug("stream from {} to {} {} asking for dialback", dfrom, to, streamID);
- if (dfrom.endsWith(xmpp.getJid().toEscapedString()) && (dfrom.equals(xmpp.getJid().toEscapedString())
- || dfrom.endsWith("." + xmpp.getJid()))) {
- logger.warn("stream from {} is invalid", dfrom);
- break;
- }
- if (to != null && to.equals(xmpp.getJid().toEscapedString())) {
- String dbKey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- xmpp.startDialback(Jid.of(dfrom), streamID, dbKey);
- } else {
- logger.warn("stream from " + dfrom + " " + streamID + " invalid to " + to);
- break;
- }
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String vfrom = parser.getAttributeValue(null, "from");
- String vto = parser.getAttributeValue(null, "to");
- String vid = parser.getAttributeValue(null, "id");
- String vkey = XmlUtils.getTagText(parser);
- updateTsRemoteData();
- final boolean[] valid = {false};
- if (vfrom != null && vto != null && vid != null && vkey != null) {
- xmpp.getConnectionOut(Jid.of(vfrom), false).ifPresent(c -> {
- String dialbackKey = c.dbKey;
- valid[0] = vkey.equals(dialbackKey);
- });
- }
- if (valid[0]) {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='valid'/>");
- logger.debug("stream from {} {} dialback verify valid", vfrom, streamID);
- setAuthenticated(true);
- } else {
- sendStanza("<db:verify from='" + vto + "' to='" + vfrom + "' id='" + vid + "' type='invalid'/>");
- logger.warn("stream from {} {} dialback verify invalid", vfrom, streamID);
- }
- } else if (tag.equals("presence") && checkFromTo(parser) && isAuthenticated()) {
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} presence: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- } else if (tag.equals("message") && checkFromTo(parser)) {
- updateTsRemoteData();
- String xml = XmlUtils.parseToString(parser, false);
- logger.debug("stream {} message: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
-
- } else if (tag.equals("iq") && checkFromTo(parser) && isAuthenticated()) {
- updateTsRemoteData();
- String type = parser.getAttributeValue(null, "type");
- String xml = XmlUtils.parseToString(parser, false);
- if (type == null || !type.equals("error")) {
- logger.debug("stream {} iq: {}", streamID, xml);
- xmpp.onStanzaReceived(xml);
- }
- } else if (!isSecured() && tag.equals("starttls") && !isAuthenticated()) {
- listener.starttls(this);
- } else if (isSecured() && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- sendOpenStream(null, true);
- } else if (isSecured() && tag.equals("auth") && parser.getNamespace().equals(NS_SASL)
- && parser.getAttributeValue(null, "mechanism").equals("EXTERNAL")
- && !isAuthenticated() && isTrusted()) {
- sendStanza("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
- logger.info("stream {} authenticated externally", streamID);
- this.from.add(Jid.of(from));
- setAuthenticated(true);
- restartParser();
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- logger.debug("Stream error {} from {}: {}", streamError.getCondition(), streamID, streamError.getText());
- xmpp.removeConnectionIn(this);
- closeConnection();
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, true);
- logger.warn("Unhandled stanza from {}: {}", streamID, unhandledStanza);
- }
- }
- logger.warn("stream {} finished", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (EOFException | SocketException ex) {
- logger.debug("stream {} closed (dirty)", streamID);
- xmpp.removeConnectionIn(this);
- closeConnection();
- } catch (Exception e) {
- logger.debug("stream {} error {}", streamID, e);
- xmpp.removeConnectionIn(this);
- closeConnection();
- }
- }
-
- void updateTsRemoteData() {
- received = Instant.now();
- }
-
- void sendOpenStream(String from, boolean xmppversionnew) throws IOException {
- String openStream = "<?xml version='1.0'?><stream:stream xmlns='jabber:server' " +
- "xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- xmpp.getJid().toEscapedString() + "' id='" + streamID + "' version='1.0'>";
- if (xmppversionnew) {
- openStream += "<stream:features>";
- if (listener != null && listener.isTlsAvailable() && !Arrays.asList(xmpp.brokenSSLhosts).contains(from)) {
- if (!isSecured()) {
- openStream += "<starttls xmlns='" + NS_TLS + "'><optional/></starttls>";
- } else if (!isAuthenticated() && isTrusted()) {
- openStream += "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" +
- "<mechanism>EXTERNAL</mechanism>" +
- "</mechanisms>";
- }
- }
- openStream += "</stream:features>";
- }
- sendStanza(openStream);
- }
-
- public void sendDialbackResult(Jid sfrom, String type) {
- sendStanza("<db:result from='" + xmpp.getJid().toEscapedString() + "' to='" + sfrom + "' type='" + type + "'/>");
- if (type.equals("valid")) {
- from.add(sfrom);
- logger.debug("stream from {} {} ready", sfrom, streamID);
- setAuthenticated(true);
- }
- }
-
- boolean checkFromTo(XmlPullParser parser) throws Exception {
- String cfrom = parser.getAttributeValue(null, "from");
- String cto = parser.getAttributeValue(null, "to");
- if (StringUtils.isNotEmpty(cfrom) && StringUtils.isNotEmpty(cto)) {
- Jid jidfrom = Jid.of(cfrom);
- for (Jid aFrom : from) {
- if (aFrom.equals(Jid.of(jidfrom.getDomain()))) {
- return true;
- }
- }
- }
- logger.warn("rejected from {}, to {}, stream {}", cfrom, cto, from.stream().collect(Collectors.joining(",")));
- return false;
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
deleted file mode 100644
index 4c32b9ae..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionListener.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.juick.server.xmpp.s2s;
-
-
-import com.juick.server.xmpp.router.StreamError;
-
-public interface ConnectionListener {
- boolean isTlsAvailable();
- void starttls(ConnectionIn connection);
- void proceed(ConnectionOut connection);
- void verify(ConnectionOut connection, String from, String type, String sid);
- void dialbackError(ConnectionOut connection, StreamError error);
- void finished(ConnectionOut connection, boolean dirty);
- void exception(ConnectionOut connection, Exception ex);
- void ready(ConnectionOut connection);
- boolean securing(ConnectionOut connection);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
deleted file mode 100644
index be485ab1..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/ConnectionOut.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import com.juick.server.xmpp.router.Stream;
-import com.juick.server.xmpp.router.StreamError;
-import com.juick.server.xmpp.router.StreamFeatures;
-import com.juick.server.xmpp.router.XmlUtils;
-import com.juick.server.xmpp.s2s.util.DialbackUtils;
-import org.apache.commons.codec.Charsets;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.text.RandomStringGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xmlpull.v1.XmlPullParser;
-import rocks.xmpp.addr.Jid;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.SocketException;
-import java.util.UUID;
-
-import static com.juick.server.xmpp.router.StreamNamespaces.NS_STREAM;
-import static com.juick.server.xmpp.s2s.Connection.NS_SASL;
-
-/**
- * @author ugnich
- */
-public class ConnectionOut extends Stream {
- protected static final Logger logger = LoggerFactory.getLogger(ConnectionOut.class);
- public static final String NS_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
- public static final String NS_DB = "jabber:server:dialback";
- private boolean secured = false;
- private boolean trusted = false;
- public boolean streamReady = false;
- String checkSID = null;
- String dbKey = null;
- private String streamID;
- ConnectionListener listener;
- RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
-
- public ConnectionOut(Jid from, Jid to, InputStream is, OutputStream os, String checkSID, String dbKey) throws Exception {
- super(from, to, is, os);
- this.to = to;
- this.checkSID = checkSID;
- this.dbKey = dbKey;
- if (dbKey == null) {
- this.dbKey = DialbackUtils.generateDialbackKey(generator.generate(15), to, from, streamID);
- }
- streamID = UUID.randomUUID().toString();
- }
-
- public void sendOpenStream() throws IOException {
- send("<?xml version='1.0'?><stream:stream xmlns='jabber:server' id='" + streamID +
- "' xmlns:stream='http://etherx.jabber.org/streams' xmlns:db='jabber:server:dialback' from='" +
- from.toEscapedString() + "' to='" + to.toEscapedString() + "' version='1.0'>");
- }
-
- void processDialback() throws Exception {
- if (checkSID != null) {
- sendDialbackVerify(checkSID, dbKey);
- }
- send("<db:result from='" + from.toEscapedString() + "' to='" + to.toEscapedString() + "'>" +
- dbKey + "</db:result>");
- }
-
- @Override
- public void handshake() {
- try {
- restartStream();
-
- sendOpenStream();
-
- parser.next(); // stream:stream
- streamID = parser.getAttributeValue(null, "id");
- if (streamID == null || streamID.isEmpty()) {
- throw new Exception("stream to " + to + " invalid first packet");
- }
-
- logger.debug("stream to {} {} open", to, streamID);
- boolean xmppversionnew = parser.getAttributeValue(null, "version") != null;
- if (!xmppversionnew) {
- processDialback();
- }
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String tag = parser.getName();
- if (tag.equals("result") && parser.getNamespace().equals(NS_DB)) {
- String type = parser.getAttributeValue(null, "type");
- if (type != null && type.equals("valid")) {
- streamReady = true;
- listener.ready(this);
- } else {
- logger.warn("stream to {} {} dialback fail", to, streamID);
- }
- XmlUtils.skip(parser);
- } else if (tag.equals("verify") && parser.getNamespace().equals(NS_DB)) {
- String from = parser.getAttributeValue(null, "from");
- String type = parser.getAttributeValue(null, "type");
- String sid = parser.getAttributeValue(null, "id");
- listener.verify(this, from, type, sid);
- XmlUtils.skip(parser);
- } else if (tag.equals("features") && parser.getNamespace().equals(NS_STREAM)) {
- StreamFeatures features = StreamFeatures.parse(parser);
- if (listener != null && !secured && features.STARTTLS >= 0
- && listener.securing(this)) {
- logger.debug("stream to {} {} securing", to.toEscapedString(), streamID);
- send("<starttls xmlns=\"" + NS_TLS + "\" />");
- } else if (secured && features.EXTERNAL >=0) {
- String authid = Base64.encodeBase64String(from.toEscapedString().getBytes(Charsets.UTF_8));
- send(String.format("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='EXTERNAL'>%s</auth>", authid));
- } else if (secured && streamReady) {
- listener.ready(this);
- } else {
- processDialback();
- }
- } else if (tag.equals("proceed") && parser.getNamespace().equals(NS_TLS)) {
- listener.proceed(this);
- } else if (tag.equals("success") && parser.getNamespace().equals(NS_SASL)) {
- streamReady = true;
- restartStream();
- sendOpenStream();
- } else if (secured && tag.equals("stream") && parser.getNamespace().equals(NS_STREAM)) {
- streamID = parser.getAttributeValue(null, "id");
- } else if (tag.equals("error")) {
- StreamError streamError = StreamError.parse(parser);
- listener.dialbackError(this, streamError);
- } else {
- String unhandledStanza = XmlUtils.parseToString(parser, false);
- logger.warn("Unhandled stanza from {} {} : {}", to, streamID, unhandledStanza);
- }
- }
- listener.finished(this, false);
- } catch (EOFException | SocketException eofex) {
- listener.finished(this, true);
- } catch (Exception e) {
- listener.exception(this, e);
- }
- }
-
- public void sendDialbackVerify(String sid, String key) {
- send("<db:verify from='" + from.toEscapedString() + "' to='" + to + "' id='" + sid + "'>" +
- key + "</db:verify>");
- }
- public void setListener(ConnectionListener listener) {
- this.listener = listener;
- }
-
- public String getStreamID() {
- return streamID;
- }
-
- public boolean isSecured() {
- return secured;
- }
-
- public void setSecured(boolean secured) {
- this.secured = secured;
- }
-
- public boolean isTrusted() {
- return trusted;
- }
-
- public void setTrusted(boolean trusted) {
- this.trusted = trusted;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
deleted file mode 100644
index 1367d333..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/DNSQueries.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-import org.apache.commons.lang3.math.NumberUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-import java.util.Hashtable;
-import java.util.Random;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-/**
- *
- * @author ugnich
- */
-public class DNSQueries {
-
- private static final Logger logger = LoggerFactory.getLogger(DNSQueries.class);
-
- private static Random rand = new Random();
-
- public static InetSocketAddress getServerAddress(String hostname) {
-
- String host = hostname;
- int port = 5269;
-
- Hashtable<String, String> env = new Hashtable<>(5);
- env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
- try {
- DirContext ctx = new InitialDirContext(env);
- Attribute att = ctx.getAttributes("_xmpp-server._tcp." + hostname, new String[]{"SRV"}).get("SRV");
-
- if (att != null && att.size() > 0) {
- int i = rand.nextInt(att.size());
- String srv[] = att.get(i).toString().split(" ");
- port = NumberUtils.toInt(srv[2], 5269);
- host = srv[3];
- }
- ctx.close();
- } catch (NamingException e) {
- logger.debug("SRV record for {} is not resolved, falling back to A record", hostname);
- }
- return new InetSocketAddress(host, port);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
deleted file mode 100644
index 6932298f..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/StanzaListener.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s;
-
-
-import rocks.xmpp.core.stanza.model.Stanza;
-
-/**
- * Created by vitalyster on 07.12.2016.
- */
-public interface StanzaListener {
- void stanzaReceived(Stanza xmlValue);
-}
diff --git a/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java b/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
deleted file mode 100644
index d25dbad8..00000000
--- a/juick-server/src/main/java/com/juick/server/xmpp/s2s/util/DialbackUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.server.xmpp.s2s.util;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.codec.digest.HmacAlgorithms;
-import org.apache.commons.codec.digest.HmacUtils;
-import rocks.xmpp.addr.Jid;
-
-/**
- * Created by vitalyster on 05.12.2016.
- */
-public class DialbackUtils {
- private DialbackUtils() {
- throw new IllegalStateException();
- }
-
- public static String generateDialbackKey(String secret, Jid to, Jid from, String id) {
- return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, DigestUtils.sha256(secret))
- .hmacHex(to.toEscapedString() + " " + from.toEscapedString() + " " + id);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/ActivityPubService.java b/juick-server/src/main/java/com/juick/service/ActivityPubService.java
deleted file mode 100644
index 892022cf..00000000
--- a/juick-server/src/main/java/com/juick/service/ActivityPubService.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.juick.service;
-
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.util.List;
-
-@Repository
-public class ActivityPubService extends BaseJdbcService implements SocialService {
- @Value("${ap_base_uri:http://localhost:8080/}")
- private String baseUri;
- @Inject
- private UserService userService;
-
- @Transactional(readOnly = true)
- @Override
- public @Nonnull User getUserByAccountUri(String acct) {
- UriComponents baseUriComponents = UriComponentsBuilder.fromUriString(baseUri).build();
- UriComponents acctComponents = UriComponentsBuilder.fromUriString(acct).build();
- if (acctComponents.getHost().equals(baseUriComponents.getHost())) {
- // /u/ugnich -> ugnich
- String userName = acctComponents.getPath().substring(3);
- return userService.getUserByName(userName);
- }
- return AnonymousUser.INSTANCE;
- }
-
- @Transactional(readOnly = true)
- @Override
- public @Nonnull List<String> getFollowers(User user) {
- return getJdbcTemplate().queryForList("SELECT acct FROM followers WHERE user_id=?", String.class, user.getUid());
- }
-
- @Transactional
- @Override
- public void addFollower(User user, String acct) {
- getJdbcTemplate().update("INSERT INTO followers(user_id, acct) " +
- "VALUES(?, ?)", user.getUid(), acct);
- }
-
- @Transactional
- @Override
- public void removeFollower(User user, String acct) {
- getJdbcTemplate().update("DELETE FROM followers WHERE user_id=? AND acct=?", user.getUid(), acct);
- }
-
- @Transactional
- @Override
- public void removeAccount(String acct) {
- getJdbcTemplate().update("DELETE FROM followers WHERE acct=?", acct);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/BaseJdbcService.java b/juick-server/src/main/java/com/juick/service/BaseJdbcService.java
deleted file mode 100644
index 496a04ba..00000000
--- a/juick-server/src/main/java/com/juick/service/BaseJdbcService.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
-
-import javax.inject.Inject;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-public class BaseJdbcService {
- @Inject
- JdbcTemplate jdbcTemplate;
- @Inject
- NamedParameterJdbcTemplate namedParameterJdbcTemplate;
-
- public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
- return namedParameterJdbcTemplate;
- }
-
- public JdbcTemplate getJdbcTemplate() {
- return jdbcTemplate;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/CrosspostServiceImpl.java b/juick-server/src/main/java/com/juick/service/CrosspostServiceImpl.java
deleted file mode 100644
index d190faba..00000000
--- a/juick-server/src/main/java/com/juick/service/CrosspostServiceImpl.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.ExternalToken;
-import com.juick.model.ApplicationStatus;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-import java.util.Optional;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class CrosspostServiceImpl extends BaseJdbcService implements CrosspostService {
-
- @Transactional(readOnly = true)
- @Override
- public Optional<ExternalToken> getTwitterToken(final int uid) {
- List<ExternalToken> list = getJdbcTemplate().query(
- "SELECT uname, access_token, access_token_secret FROM twitter WHERE user_id = ? AND crosspost = 1",
- (rs, num) -> new ExternalToken(rs.getString(1), "twitter",
- rs.getString(2), rs.getString(3)),
- uid);
-
- return list.isEmpty() ?
- Optional.empty() : Optional.of(list.get(0));
- }
-
- @Transactional
- @Override
- public boolean deleteTwitterToken(Integer uid) {
- return getJdbcTemplate().update("DELETE FROM twitter WHERE user_id=?", uid) > 0;
- }
-
- @Override
- public void addFacebookState(String state, String redirectUri) {
- jdbcTemplate.update("INSERT INTO facebook(loginhash, fb_link) VALUES(?, ?)", state, redirectUri);
- }
-
- @Override
- public void addVKState(String state, String redirectUri) {
- jdbcTemplate.update("INSERT INTO vk(loginhash, vk_link) VALUES(?, ?)", state, redirectUri);
- }
-
- @Override
- public String verifyFacebookState(String state) {
- try {
- return jdbcTemplate.queryForObject("SELECT fb_link FROM facebook WHERE loginhash=?",
- String.class, state);
- } catch (EmptyResultDataAccessException e) {
- return StringUtils.EMPTY;
- }
- }
-
- @Override
- public String verifyVKState(String state) {
- try {
- return jdbcTemplate.queryForObject("SELECT vk_link FROM vk WHERE loginhash=?",
- String.class, state);
- } catch (EmptyResultDataAccessException e) {
- return StringUtils.EMPTY;
- }
- }
-
- @Transactional(readOnly = true)
- @Override
- public Optional<Pair<String, String>> getFacebookTokens(final int uid) {
- List<Optional<Pair<String, String>>> list = getJdbcTemplate().query(
- "SELECT fb_id, access_token FROM facebook WHERE user_id = ? AND access_token IS NOT NULL AND crosspost = 1",
- (rs, num) -> Optional.of(Pair.of(rs.getString(1), rs.getString(2))),
- uid);
- return list.isEmpty() ?
- Optional.empty() : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public ApplicationStatus getFbCrossPostStatus(final int uid) {
- List<ApplicationStatus> list = getJdbcTemplate().query(
- "SELECT 1, crosspost FROM facebook WHERE user_id = ? LIMIT 1",
- (rs, num) -> {
- ApplicationStatus status = new ApplicationStatus();
-
- status.setConnected(rs.getInt(1) > 0);
- status.setCrosspostEnabled(rs.getBoolean(2));
-
- return status;
- },
- uid);
-
- return list.isEmpty() ?
- new ApplicationStatus() : list.get(0);
- }
-
- @Transactional
- @Override
- public boolean enableFBCrosspost(Integer uid) {
- return getJdbcTemplate().update("UPDATE facebook SET crosspost=1 WHERE user_id=?", uid) > 0;
- }
-
- @Transactional
- @Override
- public void disableFBCrosspost(Integer uid) {
- getJdbcTemplate().update("UPDATE facebook SET crosspost=0 WHERE user_id=?", uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getTwitterName(final int uid) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT uname FROM twitter WHERE user_id = ?",
- String.class,
- uid);
-
- return list.isEmpty() ?
- StringUtils.EMPTY : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getTelegramName(final int uid) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT tg_name FROM telegram WHERE user_id = ?",
- String.class,
- uid);
-
- return list.isEmpty() ?
- StringUtils.EMPTY : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public Optional<Pair<String, String>> getVkTokens(final int uid) {
- List<Optional<Pair<String, String>>> list = getJdbcTemplate().query(
- "SELECT vk_id, access_token FROM vk WHERE user_id = ? AND crosspost = 1",
- (rs, num) -> Optional.of(Pair.of(rs.getString(1), rs.getString(2))),
- uid);
-
- return list.isEmpty() ?
- Optional.empty() : list.get(0);
- }
-
- @Transactional
- @Override
- public void deleteVKUser(Integer uid) {
- getJdbcTemplate().update("DELETE FROM vk WHERE user_id=?", uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUIDbyFBID(long fbID) {
- try {
- return getJdbcTemplate().queryForObject("SELECT user_id FROM facebook WHERE fb_id=? AND user_id IS NOT NULL",
- Integer.class, fbID);
- } catch (EmptyResultDataAccessException e) {
- return 0;
- }
- }
-
- @Transactional
- @Override
- public boolean createFacebookUser(long fbID, String loginhash, String token, String fbName, String fbLink) {
- return getJdbcTemplate().update("UPDATE facebook SET fb_id=?, access_token=?, fb_name=?, fb_link=? WHERE loginhash=?",
- fbID, token, fbName, fbLink, loginhash) > 0;
- }
-
- @Transactional
- @Override
- public boolean updateFacebookUser(long fbID, String token, String fbName, String fbLink) {
- return getJdbcTemplate().update("UPDATE facebook SET access_token=?,fb_name=?,fb_link=? WHERE fb_id=?",
- token, fbName, fbLink, fbID) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUIDbyVKID(long vkID) {
- try {
- return getJdbcTemplate().queryForObject("SELECT user_id FROM vk WHERE vk_id=? AND user_id IS NOT NULL", Integer.class, vkID);
- } catch (EmptyResultDataAccessException e) {
- return 0;
- }
- }
-
- @Transactional
- @Override
- public boolean createVKUser(long vkID, String loginhash, String token, String vkName, String vkLink) {
- return getJdbcTemplate().update("INSERT INTO vk(vk_id,loginhash,access_token,vk_name,vk_link) VALUES (?,?,?,?,?)",
- vkID, loginhash, token, vkName, vkLink) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getFacebookNameByHash(String hash) {
- try {
- List<Pair<String, String>> fb = getJdbcTemplate().query("SELECT fb_name,fb_link FROM facebook WHERE loginhash=?",
- (rs, num) -> Pair.of(rs.getString(1), rs.getString(2)), hash);
- if (fb.size() > 0) {
- return "<a href=\"" + fb.get(0).getRight() + "\" rel=\"nofollow\">" + fb.get(0).getLeft() + "</a>";
- }
- return null;
- } catch (EmptyResultDataAccessException e) {
- return null;
- }
- }
-
- @Transactional
- @Override
- public String getTelegramNameByHash(String hash) {
- try {
- String name = getJdbcTemplate().queryForObject("SELECT tg_name FROM telegram WHERE loginhash=?", String.class, hash);
- return "<a href=\"https://telegram.me/" + name + "\" rel=\"nofollow\">" + name + "</a>";
- } catch (EmptyResultDataAccessException e) {
- return null;
- }
- }
-
- @Transactional
- @Override
- public boolean setFacebookUser(String hash, int uid) {
- return getJdbcTemplate().update("UPDATE facebook SET user_id=?,loginhash=NULL WHERE loginhash=?", uid, hash) > 0;
- }
-
- @Transactional
- @Override
- public String getVKNameByHash(String hash) {
- List<Pair<String, String>> logins = getJdbcTemplate().query("SELECT vk_name,vk_link FROM vk WHERE loginhash=?",
- (rs, num) -> Pair.of(rs.getString(1), rs.getString(2)), hash);
- if (logins.size() > 0) {
- return "<a href=\"http://vk.com/" + logins.get(0).getRight() + "\" rel=\"nofollow\">" + logins.get(0).getLeft() + "</a>";
- }
- return null;
- }
-
- @Transactional
- @Override
- public boolean setVKUser(String hash, int uid) {
- return getJdbcTemplate().update("UPDATE vk SET user_id=?,loginhash=NULL WHERE loginhash=?", uid, hash) > 0;
- }
-
- @Transactional
- @Override
- public boolean setTelegramUser(String hash, int uid) {
- return getJdbcTemplate().update("UPDATE telegram SET user_id=?,loginhash=NULL WHERE loginhash=?", uid, hash) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getJIDByHash(String hash) {
- try {
- return getJdbcTemplate().queryForObject("SELECT jid FROM jids WHERE loginhash=?", String.class, hash);
- } catch (EmptyResultDataAccessException e) {
- return null;
- }
- }
-
- @Transactional
- @Override
- public boolean setJIDUser(String hash, int uid) {
- return getJdbcTemplate().update("UPDATE jids SET user_id=?,loginhash=NULL WHERE loginhash=?", uid, hash) > 0;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java b/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java
deleted file mode 100644
index 78bdd42a..00000000
--- a/juick-server/src/main/java/com/juick/service/EmailServiceImpl.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.inject.Inject;
-import java.util.List;
-
-/**
- * Created by vitalyster on 09.12.2016.
- */
-@Repository
-@Transactional
-public class EmailServiceImpl extends BaseJdbcService implements EmailService {
-
- @Override
- public boolean verifyAddressByCode(Integer userId, String code) {
- try {
- String address = getJdbcTemplate().queryForObject("SELECT account FROM auth WHERE user_id=? AND protocol='email' AND authcode=?",
- String.class, userId, code);
- addEmail(userId, address);
- getJdbcTemplate().update("DELETE FROM auth WHERE user_id=? AND authcode=?", userId, code);
- } catch (EmptyResultDataAccessException e) {
- return false;
- }
- return true;
- }
-
- @Override
- public boolean addVerificationCode(Integer userId, String account, String code) {
- return getJdbcTemplate().update("INSERT INTO auth(user_id,protocol,account,authcode) VALUES (?,'email',?,?)",
- userId, account, code) > 0;
- }
-
- @Override
- public boolean addEmail(Integer userId, String email) {
- return getJdbcTemplate().update("INSERT INTO emails(user_id,email, subscr_hour) VALUES (?,?, 1)", userId, email) > 0;
- }
-
- @Override
- public boolean deleteEmail(Integer userId, String account) {
- return getNamedParameterJdbcTemplate().update("DELETE FROM emails " +
- "WHERE (SELECT COUNT(*) cnt FROM (select user_id, email FROM emails e) c WHERE user_id=:uid) > 1 " +
- "AND user_id=:uid AND email=:email",
- new MapSqlParameterSource()
- .addValue("uid", userId)
- .addValue("email", account)) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getNotificationsEmail(Integer userId) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT email FROM emails WHERE user_id=? AND subscr_hour IS NOT NULL", String.class, userId);
- return list.isEmpty() ? StringUtils.EMPTY : list.get(0);
- }
-
- @Override
- public boolean setNotificationsEmail(Integer userId, String account) {
- getJdbcTemplate().update("UPDATE emails SET subscr_hour=NULL WHERE user_id=?", userId);
- return StringUtils.isNotEmpty(account) && getJdbcTemplate().update(
- "UPDATE emails SET subscr_hour=1 WHERE user_id=? AND email=?", userId, account) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getEmails(Integer userId, boolean active) {
- return getJdbcTemplate().queryForList("SELECT email FROM emails WHERE user_id=? " +
- (active ? "AND subscr_hour IS NOT NULL" : ""), String.class, userId);
- }
- @Transactional(readOnly = true)
- @Override
- public String getEmailByAuthCode(String code) {
- try {
- return getJdbcTemplate().queryForObject("SELECT account FROM auth WHERE protocol='email' AND authcode=?", String.class, code);
- } catch (EmptyResultDataAccessException e) {
- return StringUtils.EMPTY;
- }
- }
-
- @Transactional
- @Override
- public void deleteAuthCode(String code) {
- getJdbcTemplate().update("DELETE FROM auth WHERE authcode=?", code);
- }
-
-}
diff --git a/juick-server/src/main/java/com/juick/service/ImagesServiceImpl.java b/juick-server/src/main/java/com/juick/service/ImagesServiceImpl.java
deleted file mode 100644
index 67c8360e..00000000
--- a/juick-server/src/main/java/com/juick/service/ImagesServiceImpl.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.juick.service;
-
-import com.juick.Attachment;
-import com.juick.Message;
-import com.juick.Photo;
-import com.juick.server.util.ImageUtils;
-import org.springframework.util.StringUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-
-public class ImagesServiceImpl implements ImagesService {
- private ImageUtils imageUtils;
- private String imgDir;
- private String tmpDir;
- public ImagesServiceImpl(String imgDir, String tmpDir) {
- this.imgDir = imgDir;
- this.tmpDir = tmpDir;
- imageUtils = new ImageUtils(imgDir, tmpDir);
- }
- @Override
- public void setAttachmentMetadata(String baseUrl, Message msg) throws Exception {
- if (!StringUtils.isEmpty(msg.getAttachmentType())) {
- Photo photo = new Photo();
- if (msg.getRid()> 0) {
- photo.setSmall(String.format("%sphotos-512/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType()));
- photo.setMedium(String.format("%sphotos-1024/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType()));
- photo.setThumbnail(String.format("%sps/%d-%d.%s", baseUrl, msg.getMid(), msg.getRid(), msg.getAttachmentType()));
- } else {
- photo.setSmall(String.format("%sphotos-512/%d.%s", baseUrl, msg.getMid(), msg.getAttachmentType()));
- photo.setMedium(String.format("%sphotos-1024/%d.%s", baseUrl, msg.getMid(), msg.getAttachmentType()));
- photo.setThumbnail(String.format("%sps/%d.%s", baseUrl, msg.getMid(), msg.getAttachmentType()));
- }
- msg.setPhoto(photo);
- String imageName = String.format("%s.%s", msg.getMid(), msg.getAttachmentType());
- if (msg.getRid() > 0) {
- imageName = String.format("%s-%s.%s", msg.getMid(), msg.getRid(), msg.getAttachmentType());
- }
- File fullImage = Paths.get(imgDir, "p", imageName).toFile();
- File mediumImage = Paths.get(imgDir, "photos-1024", imageName).toFile();
- File smallImage = Paths.get(imgDir, "photos-512", imageName).toFile();
- File thumbnailImage = Paths.get(imgDir, "ps", imageName).toFile();
- StringBuilder builder = new StringBuilder();
- builder.append(baseUrl);
- builder.append(msg.getAttachmentType().equals("mp4") ? "video" : "p");
- builder.append("/").append(msg.getMid());
- if (msg.getRid() > 0) {
- builder.append("-").append(msg.getRid());
- }
- builder.append(".").append(msg.getAttachmentType());
- String originalUrl = builder.toString();
-
- Attachment original = imageUtils.getAttachment(fullImage);
- original.setUrl(originalUrl);
-
- Attachment medium = imageUtils.getAttachment(mediumImage);
- medium.setUrl(photo.getMedium());
- original.setMedium(medium);
-
- Attachment small = imageUtils.getAttachment(smallImage);
- small.setUrl(photo.getSmall());
- original.setSmall(small);
-
- Attachment thumb = imageUtils.getAttachment(thumbnailImage);
- thumb.setUrl(photo.getMedium());
- original.setThumbnail(thumb);
-
- msg.setAttachment(original);
- }
- }
-
- @Override
- public void saveImageWithPreviews(String tempFilename, String outputFilename) throws IOException {
- imageUtils.saveImageWithPreviews(tempFilename, outputFilename);
- }
-
- @Override
- public void saveAvatar(String tempFilename, int uid) throws IOException {
- imageUtils.saveAvatar(tempFilename, uid);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java b/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java
deleted file mode 100644
index 0b7faf87..00000000
--- a/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java
+++ /dev/null
@@ -1,1143 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.*;
-import com.juick.model.AnonymousUser;
-import com.juick.model.PrivacyOpts;
-import com.juick.model.ResponseReply;
-import com.juick.server.util.HttpNotFoundException;
-import com.juick.util.MessageUtils;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.dao.IncorrectResultSizeDataAccessException;
-import org.springframework.jdbc.core.ConnectionCallback;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.jdbc.core.namedparam.SqlParameterSource;
-import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.inject.Inject;
-import java.net.URI;
-import java.sql.*;
-import java.time.Instant;
-import java.util.*;
-import java.util.Date;
-import java.util.stream.Collectors;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class MessagesServiceImpl extends BaseJdbcService implements MessagesService {
- private static final Logger logger = LoggerFactory.getLogger(MessagesServiceImpl.class);
- @Inject
- private UserService userService;
- @Inject
- private TagService tagService;
- @Inject
- private SearchService searchService;
- @Inject
- private ImagesService imagesService;
- @Value("${img_url:https://i.juick.com/}")
- private String baseImagesUrl;
-
- private class MessageMapper implements RowMapper<Message> {
- @Override
- public Message mapRow(ResultSet rs, int rowNum) throws SQLException {
- Message msg = new Message();
- msg.setMid(rs.getInt(1));
- msg.setRid(rs.getInt(2));
- msg.setReplyto(rs.getInt(3));
- User user = new User();
- user.setUid(rs.getInt(4));
- user.setName(Optional.ofNullable(rs.getString(5)).orElse(AnonymousUser.INSTANCE.getName()));
- user.setBanned(rs.getBoolean(6));
- user.setUri(URI.create(Optional.ofNullable(rs.getString(22)).orElse(StringUtils.EMPTY)));
- msg.setUser(user);
- msg.setTimestamp(rs.getTimestamp(7).toInstant());
- msg.ReadOnly = rs.getBoolean(8);
- msg.setPrivacy(rs.getInt(9));
- msg.FriendsOnly = msg.getPrivacy() < 0;
- msg.setReplies(rs.getInt(10));
- msg.setAttachmentType(rs.getString(11));
- msg.setLikes(rs.getInt(12));
- msg.Hidden = rs.getBoolean(13);
- String tagsStr = rs.getString(14);
- msg.setTags(MessageUtils.parseTags(tagsStr));
- msg.setRepliesBy(rs.getString(15));
- msg.setText(rs.getString(16));
- msg.setReplyQuote(MessageUtils.formatQuote(rs.getString(17)));
- msg.setUpdated(rs.getTimestamp(18).toInstant());
- int quoteUid = rs.getInt(19);
- User quoteUser = new User();
- quoteUser.setUid(quoteUid);
- quoteUser.setName(rs.getString(20));
- if (quoteUid == 0) {
- quoteUser.setName(AnonymousUser.INSTANCE.getName());
- quoteUser.setUri(URI.create(Optional.ofNullable(rs.getString(23)).orElse(StringUtils.EMPTY)));
- }
- msg.setTo(quoteUser);
- msg.setUpdatedAt(rs.getTimestamp(21).toInstant());
- msg.setReplyUri(URI.create(Optional.ofNullable(rs.getString(24)).orElse(StringUtils.EMPTY)));
- msg.setHtml(rs.getBoolean(25));
- if (StringUtils.isNotEmpty(msg.getAttachmentType())) {
- try {
- imagesService.setAttachmentMetadata(baseImagesUrl, msg);
- } catch (Exception e) {
- logger.warn("exception reading images for mid {} rid {}", msg.getMid(), msg.getRid(), e);
- }
- }
- return msg;
- }
- }
-
-
-
- /**
- * @see <a href="https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-type-conversions.html">Java, JDBC and MySQL Types</a>
- */
- @Transactional
- @Override
- public int createMessage(final int uid, final String txt, final String attachment, final Collection<com.juick.Tag> tags) {
- SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(getJdbcTemplate()).withTableName("messages")
- .usingColumns("user_id", "attach", "ts")
- .usingGeneratedKeyColumns("message_id");
- Map<String, Object> insertMap = new HashMap<>();
- insertMap.put("user_id", uid);
- Instant now = Instant.now();
- insertMap.put("ts", Timestamp.from(now));
- if (StringUtils.isNotEmpty(attachment)) {
- insertMap.put("attach", attachment);
- }
- int mid = simpleJdbcInsert.executeAndReturnKey(insertMap).intValue();
- if (mid > 0) {
- String tagsNames = StringUtils.EMPTY;
-
- if (CollectionUtils.isNotEmpty(tags)) {
- StringBuilder tasNamesBuilder = new StringBuilder();
- List<Object[]> params = new ArrayList<>(tags.size());
-
- boolean next = false;
-
- for (Tag tag : tags) {
- if (next) {
- tasNamesBuilder.append(" ");
- } else
- next = true;
-
- tasNamesBuilder.append(tag.getName());
- params.add(new Object[]{mid, tag.TID});
- }
- tagsNames = tasNamesBuilder.toString();
-
- getJdbcTemplate().batchUpdate(
- "INSERT INTO messages_tags(message_id, tag_id) VALUES (?, ?)",
- params, new int[]{Types.INTEGER, Types.INTEGER});
- }
-
- getJdbcTemplate().update(
- "INSERT INTO messages_txt(message_id, tags, txt, updated_at) VALUES (?, ?, ?, ?)",
- new Object[]{mid, tagsNames, txt, Timestamp.from(now)},
- new int[]{Types.INTEGER, Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP});
- getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", Timestamp.from(now), Timestamp.from(now), uid);
- }
-
- return mid;
- }
-
- /**
- * @param mid
- * @param rid
- * @param user
- * @param txt
- * @param attachment
- * @return
- * @see <a href="https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-type-conversions.html">Java, JDBC and MySQL Types</a>
- */
- @Transactional
- @Override
- public int createReply(final int mid, final int rid, final User user, final String txt, final String attachment) {
- int ridnew = getReplyIDIncrement(mid);
- Date ts = Date.from(Instant.now());
- getJdbcTemplate().update("INSERT INTO replies(message_id, reply_id, user_id, replyto, attach, txt, ts, updated_at, user_uri) " +
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
- mid, ridnew, user.getUid(), rid, attachment, txt, ts, ts, user.getUri().toASCIIString());
-
- if (ridnew > 0) {
- getJdbcTemplate().update(
- "UPDATE messages SET replies = replies + 1, updated=? WHERE message_id = ?",
- ts, mid);
- setLastReadComment(user, mid, ridnew);
- getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", ts, ts, user.getUid());
- }
- return ridnew;
- }
-
- @Override
- public int getReplyIDIncrement(final int mid) {
- return getJdbcTemplate().execute((ConnectionCallback<Integer>) conn -> {
- conn.setAutoCommit(false);
- final int replyNo;
- try (PreparedStatement ps = conn.prepareStatement("SELECT maxreplyid+1 FROM messages WHERE message_id=? FOR UPDATE")) {
- ps.setInt(1, mid);
- try (ResultSet resultSet = ps.executeQuery()) {
- if (resultSet.next()) {
- replyNo = resultSet.getInt(1);
- } else {
- throw new IncorrectResultSizeDataAccessException("while getting getReplyIDIncrement, mid=" + mid, 1, 0);
- }
- }
- }
- try (PreparedStatement ps = conn.prepareStatement("UPDATE messages SET maxreplyid=? WHERE message_id=?")) {
- ps.setInt(1, replyNo);
- ps.setInt(2, mid);
- if (ps.executeUpdate() != 1) {
- throw new IncorrectResultSizeDataAccessException("Cannot find a message to update: " + mid, 1, 0);
- }
- }
- conn.commit();
- return replyNo;
- });
-
- }
-
- @Transactional
- void updateRepliesBy(int mid) {
- List<String> users = getJdbcTemplate().queryForList("SELECT users.nick FROM replies " +
- "INNER JOIN users ON replies.user_id=users.id WHERE replies.message_id=? " +
- "GROUP BY replies.user_id ORDER BY COUNT(replies.reply_id) DESC LIMIT 5", String.class, mid);
- String result = users.stream().map(u -> "@" + u).collect(Collectors.joining(","));
- getJdbcTemplate().update("UPDATE messages_txt SET repliesby=? WHERE message_id=?", result, mid);
- }
-
- @Transactional
- @Override
- public RecommendStatus recommendMessage(final int mid, final int vuid, final String userUri) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", vuid)
- .addValue("uri", userUri)
- .addValue("like_id", Reaction.LIKE)
- .addValue("mid", mid);
- int wasDeleted = getNamedParameterJdbcTemplate()
- .update("DELETE FROM favorites WHERE user_id=:uid AND message_id=:mid AND like_id=:like_id AND user_uri=:uri", sqlParameterSource);
- if (wasDeleted > 0) {
- return RecommendStatus.Deleted;
- } else {
- boolean wasAdded = getJdbcTemplate()
- .update("INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", vuid, mid,Reaction.LIKE, userUri) == 1;
- if (wasAdded) {
- return RecommendStatus.Added;
- }
- }
- return RecommendStatus.Error;
- }
-
- @Override
- public RecommendStatus recommendMessage(int mid, int vuid) {
- return recommendMessage(mid, vuid, StringUtils.EMPTY);
- }
-
- @Override
- public List<Reaction> listReactions() {
- return jdbcTemplate.query("SELECT like_id, description FROM reactions", (rs, rowNum) -> {
- Reaction reaction = new Reaction(rs.getInt("like_id"));
- reaction.setDescription(rs.getString("description"));
- return reaction;
- });
- }
-
- @Override
- public RecommendStatus likeMessage(int mid, int vuid, int reactionId) {
- return likeMessage(mid, vuid, reactionId, StringUtils.EMPTY);
- }
-
- @Transactional
- @Override
- public RecommendStatus likeMessage(int mid, int vuid, int reactionId, String userUri) throws IllegalArgumentException {
- boolean wasAdded = getJdbcTemplate()
- .update("INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", vuid, mid, reactionId, userUri) == 1;
- if (wasAdded) {
- return RecommendStatus.Added;
- }
-
- return RecommendStatus.Error;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean canViewThread(final int mid, final int uid) {
- List<PrivacyOpts> list = getJdbcTemplate().query(
- "SELECT user_id, privacy FROM messages WHERE message_id = ?",
- (rs, rowNum) -> {
- PrivacyOpts res = new PrivacyOpts();
-
- res.setUid(rs.getInt(1));
- res.setPrivacy(rs.getInt(2));
-
- return res;
- },
- mid);
-
- PrivacyOpts privacyOpts = list.isEmpty() ? null : list.get(0);
-
- return privacyOpts == null ||
- privacyOpts.getPrivacy() >= 0 ||
- uid == privacyOpts.getUid() ||
- ((privacyOpts.getPrivacy() == -1 || privacyOpts.getPrivacy() == -2) &&
- uid > 0 && userService.isInWL(privacyOpts.getUid(), uid));
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isReadOnly(final int mid) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT readonly FROM messages WHERE message_id = ?",
- new Object[]{mid},
- Integer.class);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isSubscribed(final int uid, final int mid) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM subscr_messages WHERE suser_id = ? AND message_id = ?",
- new Object[]{uid, mid},
- Integer.class);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getMessagePrivacy(final int mid) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT privacy FROM messages WHERE message_id = ?",
- new Object[]{mid},
- Integer.class);
-
- return list.isEmpty() ? -4 : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public com.juick.Message getMessage(final int mid) {
-
- List<com.juick.Message> list = getJdbcTemplate().query(
- "SELECT messages.message_id as mid, 0 as rid, 0 as replyto, "
- + "messages.user_id as uid, users.nick, users.banned as banned, "
- + ""
- + "messages.ts,"
- + "messages.readonly, messages.privacy, messages.replies,"
- + "messages.attach, COUNT(DISTINCT favorites.user_id) as likes, messages.hidden,"
- + "txt.tags, txt.repliesby, txt.txt, '' as q, messages.updated as updated, 0 as to_uid, "
- + "NULL as to_name, txt.updated_at, '' as user_uri, '' as to_uri, '' as reply_uri, 0 as html FROM messages "
- + "INNER JOIN users ON messages.user_id = users.id "
- + "INNER JOIN messages_txt AS txt "
- + "ON messages.message_id = txt.message_id "
- + "LEFT JOIN favorites "
- + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 "
- + "WHERE messages.message_id = ? "
- + "GROUP BY mid, rid, replyto, uid, nick, banned, messages.ts, readonly, "
- + "privacy, replies, attach, tags, repliesby, q, updated_at, user_uri, to_uri, reply_uri, html",
- new MessageMapper(),
- mid);
- if (!list.isEmpty()) {
- final Message message = list.get(0);
- Map<Integer, Set<Reaction>> reactionStats = updateReactionsFor(Collections.singletonList(mid));
- message.setReactions(reactionStats.get(message.getMid()));
- return message;
- }
- return null;
- }
-
- @Transactional(readOnly = true)
- @Override
- public com.juick.Message getReply(final int mid, final int rid) {
- List<com.juick.Message> list = getJdbcTemplate().query(
- "SELECT replies.user_id, users.nick,"
- + "replies.replyto, replies.ts,"
- + "replies.attach, replies.txt, IFNULL(q.txt,t.txt) as quote, "
- + "COALESCE(q.user_id, m.user_id) AS to_uid, COALESCE(qu.nick, mu.nick) AS to_name, "
- + "replies.updated_at, replies.user_uri as uri, "
- + "q.user_uri AS to_uri, replies.reply_uri AS reply_uri, replies.html, q.reply_uri "
- + "FROM replies LEFT JOIN users ON replies.user_id = users.id "
- + "LEFT JOIN replies q ON replies.message_id = q.message_id and replies.replyto = q.reply_id "
- + "LEFT JOIN messages_txt t ON replies.message_id = t.message_id "
- + "LEFT JOIN messages m ON replies.message_id = m.message_id "
- + "LEFT JOIN users qu ON q.user_id=qu.id "
- + "LEFT JOIN users mu ON m.user_id=mu.id "
- + "WHERE replies.message_id = ? AND replies.reply_id = ?",
- (rs, num) -> {
- Message msg = new Message();
-
- msg.setMid(mid);
- msg.setRid(rid);
- msg.setUser(new User());
- msg.getUser().setUid(rs.getInt(1));
- msg.getUser().setName(rs.getString(2));
- if (msg.getUser().getUid() == 0) {
- msg.getUser().setName(AnonymousUser.INSTANCE.getName());
- msg.getUser().setUri(
- URI.create(Optional.ofNullable(rs.getString(11)).orElse(StringUtils.EMPTY)));
- }
- msg.setReplyto(rs.getInt(3));
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
- msg.setAttachmentType(rs.getString(5));
- msg.setText(rs.getString(6));
- String quote = rs.getString(7);
-
- if (!StringUtils.isEmpty(quote)) {
- msg.setReplyQuote(MessageUtils.formatQuote(quote));
- }
- int quoteUid = rs.getInt(8);
- User quoteUser = new User();
- quoteUser.setUid(quoteUid);
- quoteUser.setName(Optional.ofNullable(rs.getString(9)).orElse(AnonymousUser.INSTANCE.getName()));
- quoteUser.setUri(URI.create(Optional.ofNullable(rs.getString(12)).orElse(StringUtils.EMPTY)));
- msg.setTo(quoteUser);
- msg.setUpdatedAt(rs.getTimestamp(10).toInstant());
- msg.setReplyUri(URI.create(Optional.ofNullable(rs.getString(13)).orElse(StringUtils.EMPTY)));
- msg.setHtml(rs.getBoolean(14));
- msg.setReplyToUri(URI.create(Optional.ofNullable(rs.getString(15)).orElse(StringUtils.EMPTY)));
- if (StringUtils.isNotEmpty(msg.getAttachmentType())) {
- try {
- imagesService.setAttachmentMetadata(baseImagesUrl, msg);
- } catch (Exception e) {
- logger.warn("exception reading images for mid {} rid {}", msg.getMid(), msg.getRid(), e);
- }
- }
- return msg;
- },
- mid, rid);
-
- return list.isEmpty() ? null : list.get(0);
- }
-
- @Override
- public Message getReplyByUri(String replyUri) {
- List<Message> replies = getJdbcTemplate().query("SELECT message_id, reply_id from replies WHERE reply_uri=?", (rs, rowNum) -> getReply(rs.getInt(1), rs.getInt(2)), replyUri);
- return replies.isEmpty() ? null : replies.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public User getMessageAuthor(final int mid) {
- List<User> list = getJdbcTemplate().query(
- "SELECT messages.user_id, users.nick "
- + "FROM messages INNER JOIN users ON messages.user_id = users.id WHERE messages.message_id = ?",
- new Object[]{mid},
- (rs, num) -> {
- User res = new com.juick.User();
- res.setUid(rs.getInt(1));
- res.setName(rs.getString(2));
- return res;
- });
-
- return list.isEmpty() ?
- null : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getMessageRecommendations(final int mid) {
- return getJdbcTemplate().queryForList(
- "SELECT DISTINCT users.nick FROM favorites " +
- "INNER JOIN users ON (favorites.message_id = ? AND favorites.user_id = users.id) " +
- "INNER JOIN messages m ON favorites.message_id=m.message_id WHERE favorites.like_id=1 " +
- "AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " +
- "(user_id = favorites.user_id AND bl_user_id = m.user_id) " +
- "OR (user_id = m.user_id AND bl_user_id = favorites.user_id))",
- String.class, mid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getAll(final int visitorUid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("before", before)
- .addValue("visitorUid", visitorUid);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT m.message_id FROM messages m WHERE " +
- (before > 0 ?
- " m.message_id < :before AND " : StringUtils.EMPTY) +
- " m.hidden = 0 AND (m.privacy > 0" +
- (visitorUid > 1 ?
- " OR m.user_id = :visitorUid) AND NOT EXISTS (" +
- " SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid AND b.bl_user_id = m.user_id)" :
- ")") +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :visitorUid = bt.user_id)" +
- " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :visitorUid) ORDER BY m.message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getTag(final int tid, final int visitorUid, final int before, final int cnt) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("tid", tid)
- .addValue("cnt", cnt)
- .addValue("before", before)
- .addValue("visitorUid", visitorUid);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT messages.message_id FROM (tags INNER JOIN messages_tags " +
- "ON ((tags.synonym_id = :tid OR tags.tag_id = :tid) AND tags.tag_id = messages_tags.tag_id)) " +
- "INNER JOIN messages ON messages.message_id = messages_tags.message_id WHERE " +
- (before > 0 ?
- " messages.message_id < :before AND " : StringUtils.EMPTY) +
- "(messages.privacy > 0 OR messages.user_id = :visitorUid) " +
- "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid and b.bl_user_id = messages.user_id) " +
- "ORDER BY messages.message_id DESC LIMIT :cnt",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getTags(final String tids, final int visitorUid, final int before, final int cnt) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("cnt", cnt)
- .addValue("before", before)
- .addValue("visitorUid", visitorUid);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT messages.message_id FROM messages_tags " +
- "INNER JOIN messages USING(message_id) WHERE messages_tags.tag_id IN (" + tids + ") " +
- (before > 0 ?
- " AND messages.message_id < :before " : StringUtils.EMPTY) +
- " AND (messages.privacy > 0 OR messages.user_id = :visitorUid) " +
- "ORDER BY messages.message_id DESC LIMIT :cnt",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getPlace(final int placeId, final int visitorUid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("placeId", placeId)
- .addValue("before", before)
- .addValue("visitorUid", visitorUid);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM messages WHERE place_id = :placeId " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- " AND (privacy > 0 OR user_id = :visitorUid) ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getMyFeed(final int uid, final int before, boolean recommended) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("before", before);
-
- List<Integer> mids = getNamedParameterJdbcTemplate().queryForList(
- "(SELECT message_id FROM messages " +
- " INNER JOIN subscr_users ON (subscr_users.suser_id = :uid AND subscr_users.user_id = messages.user_id) " +
- " WHERE " +
- (before > 0 ?
- " message_id < :before AND " : StringUtils.EMPTY) +
- " (privacy >= 0 OR (privacy >= -2 AND privacy <= -1" +
- " AND EXISTS (SELECT 1 FROM wl_users w WHERE w.wl_user_id = :uid and w.user_id = messages.user_id))) " +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) and :uid = bt.user_id))" +
- " UNION " +
- " (SELECT message_id FROM messages WHERE user_id=:uid " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- (recommended ?
- ") UNION " +
- " (SELECT f.message_id as message_id FROM favorites f INNER JOIN messages ON " +
- "f.message_id=messages.message_id WHERE " +
- "EXISTS (SELECT 1 FROM subscr_users s WHERE s.suser_id = :uid and f.user_id = s.user_id)" +
- (before > 0 ?
- " AND f.message_id < :before " : StringUtils.EMPTY) : StringUtils.EMPTY) +
- " AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and b.bl_user_id = messages.user_id)" +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) and :uid = bt.user_id)) " +
- "ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
-
- return mids;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getPrivate(final int uid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList
- ("SELECT message_id FROM messages WHERE user_id = :uid AND privacy < 0" +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- "ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getDiscussions(final int uid, final Long to) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("to", new Timestamp(to));
-
- if (uid == 0) {
- return getNamedParameterJdbcTemplate().query("SELECT message_id FROM messages WHERE " +
- (to != 0 ?
- " updated < :to AND" : StringUtils.EMPTY) +
- " NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" +
- " AND u.id = messages.user_id and u.id <> :uid) " +
- " ORDER BY updated DESC, message_id DESC LIMIT 20",
- sqlParameterSource,
- (rs, rowNum) -> rs.getInt(1));
- }
- return getNamedParameterJdbcTemplate().query(
- "SELECT messages.message_id, messages.updated FROM subscr_messages " +
- "INNER JOIN messages ON messages.message_id=subscr_messages.message_id " +
- "WHERE suser_id = :uid " +
- (to != 0 ?
- "AND updated < :to " : StringUtils.EMPTY) +
- " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" +
- " AND u.id = messages.user_id and u.id <> :uid) " +
- "ORDER BY updated DESC, message_id DESC LIMIT 20",
- sqlParameterSource,
- (rs, rowNum) -> rs.getInt(1));
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getRecommended(final int uid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT f.message_id FROM favorites f WHERE " +
- "EXISTS (SELECT 1 FROM subscr_users s WHERE s.suser_id = :uid and f.user_id = s.user_id)" +
- (before > 0 ?
- " AND f.message_id < :before " : StringUtils.EMPTY) +
- "ORDER BY f.message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getPopular(final int visitorUid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("vid", visitorUid)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT m.message_id FROM messages m WHERE m.privacy > 0 " +
- (before > 0 ?
- " AND m.message_id < :before " : StringUtils.EMPTY) +
- " AND m.popular > 0 AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" +
- " ORDER BY m.message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getPhotos(final int visitorUid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("vid", visitorUid)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT m.message_id FROM messages m WHERE (m.privacy > 0 OR m.user_id = :vid) " +
- (before > 0 ?
- " AND m.message_id < :before " : StringUtils.EMPTY) +
- " AND m.attach IS NOT NULL " +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " +
- "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" +
- " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :vid) " +
- " AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " +
- " ORDER BY m.message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getSearch(final User visitor, final String search, final int page) {
- return searchService.searchInAllMessages(visitor, search, page);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserBlog(final int uid, final int privacy, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("privacy", privacy)
- .addValue("before", before);
-
- ;
- if (userService.getUserByUID(uid).orElseThrow(IllegalStateException::new).isBanned()) {
- throw new HttpNotFoundException();
- }
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM messages WHERE user_id = :uid" +
- (before > 0 ?
- " AND message_id < :before" : StringUtils.EMPTY) +
- " AND privacy >= :privacy ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserTag(final int uid, final int tid, final int privacy, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("tid", tid)
- .addValue("privacy", privacy)
- .addValue("before", before);
-
- if (userService.getUserByUID(uid).orElseThrow(IllegalStateException::new).isBanned()) {
- throw new HttpNotFoundException();
- }
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT messages.message_id FROM messages_tags INNER JOIN messages " +
- " USING (message_id) WHERE messages.user_id = :uid AND messages_tags.tag_id = :tid " +
- (before > 0 ?
- " AND messages.message_id < :before " : StringUtils.EMPTY) +
- " AND messages.privacy >= :privacy ORDER BY messages.message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserBlogAtDay(final int uid, final int privacy, final int daysback) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("privacy", privacy)
- .addValue("daysback", daysback);
-
- if (userService.getUserByUID(uid).orElseThrow(IllegalStateException::new).isBanned()) {
- throw new HttpNotFoundException();
- }
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM messages WHERE user_id = :uid" +
- (daysback > 0 ?
- " AND ts >= date(NOW() - INTERVAL :daysback day)" +
- " AND ts < date(NOW() - INTERVAL :daysback day + INTERVAL 1 day)" : StringUtils.EMPTY) +
- " AND privacy >= :privacy ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserBlogWithRecommendations(final int uid, final int privacy, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("privacy", privacy)
- .addValue("before", before);
-
- if (userService.getUserByUID(uid).orElseThrow(IllegalStateException::new).isBanned()) {
- throw new HttpNotFoundException();
- }
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM " +
- "(SELECT message_id FROM favorites " +
- " WHERE user_id = :uid " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- " ORDER BY message_id DESC LIMIT 20) as r" +
- " UNION ALL " +
- "SELECT message_id FROM " +
- "(SELECT message_id FROM messages WHERE user_id = :uid" +
- (before > 0 ?
- " AND message_id < :before" : StringUtils.EMPTY) +
- " AND privacy >= :privacy ORDER BY message_id DESC LIMIT 20) as m " +
- "ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserRecommendations(final int uid, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM favorites " +
- " WHERE user_id = :uid " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- " ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserPhotos(final int uid, final int privacy, final int before) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("privacy", privacy)
- .addValue("before", before);
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT message_id FROM messages WHERE user_id = :uid " +
- (before > 0 ?
- " AND message_id < :before " : StringUtils.EMPTY) +
- " AND privacy >= :privacy AND attach IS NOT NULL ORDER BY message_id DESC LIMIT 20",
- sqlParameterSource,
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUserSearch(final User visitor, final int UID, final String search, final int privacy, final int page) {
- return searchService.searchByStringAndUser(visitor, search, UID, page);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<com.juick.Message> getMessages(final User visitor, final List<Integer> mids) {
- if (CollectionUtils.isNotEmpty(mids)) {
-
- List<com.juick.Message> msgs = getNamedParameterJdbcTemplate().query(
- "WITH RECURSIVE banned(message_id, reply_id) "
- + "AS (SELECT message_id, reply_id FROM replies WHERE replies.message_id IN (:ids) "
- + "AND (EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) "
- + "OR EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)) "
- + "UNION ALL SELECT replies.message_id, replies.reply_id FROM replies INNER JOIN banned "
- + "ON banned.reply_id = replies.replyto AND banned.message_id=replies.message_id "
- + "WHERE replies.message_id IN (:ids)) "
- + "SELECT messages.message_id, 0 as rid, 0 as replyto, "
- + "messages.user_id,users.nick, 0 as banned, "
- + "messages.ts,"
- + "messages.readonly,messages.privacy, messages.replies-COUNT(DISTINCT banned.reply_id) as replies,"
- + "messages.attach,COUNT(DISTINCT favorites.user_id) AS likes,messages.hidden,"
- + "messages_txt.tags,messages_txt.repliesby, messages_txt.txt, '' as q, "
- + "messages.updated, 0 as to_uid, NULL as to_name, messages_txt.updated_at, '' as user_uri, "
- + "'' as to_uri, '' as reply_uri, 0 as html "
- + "FROM (messages INNER JOIN messages_txt "
- + "ON messages.message_id=messages_txt.message_id) "
- + "INNER JOIN users ON messages.user_id=users.id "
- + "LEFT JOIN favorites "
- + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 "
- + "LEFT JOIN banned "
- + "ON messages.message_id = banned.message_id "
- + "WHERE messages.message_id IN (:ids) GROUP BY "
- + "messages.message_id, rid, replyto, messages.user_id, users.nick, banned, messages.ts, "
- + "messages.readonly, messages.privacy, messages.attach, messages.hidden, messages_txt.tags, "
- + "messages_txt.repliesby, messages_txt.txt, q, messages.updated, to_uid, to_name, updated_at, "
- + "user_uri, reply_uri, html",
- new MapSqlParameterSource("ids", mids)
- .addValue("uid", visitor.getUid()),
- new MessageMapper());
-
-
- Map<Integer,Set<Reaction>> likes = updateReactionsFor(mids);
-
- msgs.forEach(i -> i.setReactions(likes.get(i.getMid())));
-
- msgs.sort(Comparator.comparing(item -> mids.indexOf(item.getMid())));
-
- return msgs;
- }
- return Collections.emptyList();
- }
-
-
- @Transactional(readOnly = true)
- @Override
- public Map<Integer,Set<Reaction>> updateReactionsFor(final List<Integer> mids) {
-
- return getNamedParameterJdbcTemplate().query("select f.message_id as mid, f.like_id as lid," +
- " r.description as descr, count(f.like_id) as cnt" +
- " from favorites f LEFT JOIN reactions r ON f.like_id = r.like_id " +
- " where f.message_id IN (:mids) " +
- " group by f.message_id, f.like_id", new MapSqlParameterSource("mids", mids), (ResultSet rs) -> {
- Map<Integer,Set<Reaction>> results = new HashMap<>();
-
-
- while (rs.next()) {
- int messageId = rs.getInt("mid");
- int likeId = rs.getInt("lid");
- int count = rs.getInt("cnt");
- String description = rs.getString("descr");
- Reaction reaction = new Reaction(likeId);
- reaction.setCount(count);
- reaction.setDescription(description);
- results.computeIfAbsent(messageId, HashSet::new);
- results.get(messageId).add(reaction);
- }
-
- return results;
- });
-
- }
-
-
- @Transactional
- @Override
- public List<Message> getReplies(final User user, final int mid) {
- List<Message> replies = getNamedParameterJdbcTemplate().query(
- "WITH RECURSIVE banned(reply_id, user_id) AS (" +
- "SELECT reply_id, user_id FROM replies " +
- "WHERE replies.message_id = :mid " +
- "AND EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " +
- "UNION ALL SELECT replies.reply_id, replies.user_id FROM replies " +
- "INNER JOIN banned ON banned.reply_id = replies.replyto " +
- "WHERE replies.message_id = :mid) " +
- "SELECT replies.message_id as mid, replies.reply_id, replies.replyto, " +
- "replies.user_id, users.nick, users.banned, " +
- "replies.ts, " +
- "0 as readonly, 0 as privacy, 0 as replies, " +
- "replies.attach, 0 as likes, 0 as hidden, " +
- "NULL as tags, NULL as repliesby, replies.txt, " +
- "IFNULL(qw.txt, t.txt) as q, " +
- "NOW(), " +
- "COALESCE(qw.user_id, m.user_id) as to_uid, COALESCE(qu.nick, mu.nick) as to_name, " +
- "replies.updated_at, replies.user_uri as uri, " +
- "qw.user_uri as to_uri, replies.reply_uri, replies.html " +
- "FROM replies LEFT JOIN users " +
- "ON replies.user_id = users.id " +
- "LEFT JOIN replies qw ON replies.message_id = qw.message_id and replies.replyto = qw.reply_id " +
- "LEFT JOIN messages_txt t on replies.message_id = t.message_id " +
- "LEFT JOIN messages m on replies.message_id = m.message_id " +
- "LEFT JOIN users qu ON qw.user_id=qu.id " +
- "LEFT JOIN users mu ON m.user_id=mu.id " +
- "WHERE replies.message_id = :mid " +
- "AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)" +
- "AND NOT EXISTS (SELECT 1 FROM banned WHERE banned.reply_id = replies.reply_id) " +
- "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = m.user_id) " +
- "ORDER BY replies.reply_id ASC",
- new MapSqlParameterSource("mid", mid).addValue("uid", user.getUid()),
- new MessageMapper());
- if (replies.size() > 0) {
- setRead(user, mid);
- }
- return replies;
- }
-
- @Transactional
- @Override
- public boolean setMessagePopular(final int mid, final int popular) {
- int ret;
- MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("mid", mid)
- .addValue("popular", popular);
-
- switch (popular) {
- case -2:
- ret = getNamedParameterJdbcTemplate().update(
- "UPDATE messages SET hidden = 1 WHERE message_id = :mid",
- sqlParameterSource);
- break;
- case -1:
- sqlParameterSource.addValue("popular", 0);
- default:
- ret = getNamedParameterJdbcTemplate().update(
- "UPDATE messages SET popular = :popular WHERE message_id = :mid",
- sqlParameterSource);
- break;
- }
-
- if (popular == -1)
- ret = getNamedParameterJdbcTemplate().update(
- "INSERT INTO top_ignore_messages VALUES (:mid)",
- sqlParameterSource);
-
- return ret > 0;
- }
-
- @Transactional
- @Override
- public boolean setMessagePrivacy(final int mid) {
- return getJdbcTemplate().update("UPDATE messages SET privacy=1 WHERE message_id=?", mid) > 0;
- }
-
- @Transactional
- @Override
- public boolean deleteMessage(final int uid, final int mid) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("mid", mid)
- .addValue("uid", uid);
-
- if (getNamedParameterJdbcTemplate().update(
- "DELETE FROM messages WHERE message_id = :mid AND user_id = :uid", sqlParameterSource) > 0) {
-
- getNamedParameterJdbcTemplate().update("DELETE FROM messages_txt WHERE message_id = :mid", sqlParameterSource);
- getNamedParameterJdbcTemplate().update("DELETE FROM replies WHERE message_id = :mid", sqlParameterSource);
- getNamedParameterJdbcTemplate().update("DELETE FROM subscr_messages WHERE message_id = :mid", sqlParameterSource);
- getNamedParameterJdbcTemplate().update("DELETE FROM messages_tags WHERE message_id = :mid", sqlParameterSource);
-
- return true;
- }
- return false;
- }
- @Transactional
- @Override
- public boolean deleteReply(final int uid, final int mid, final int rid) {
- User author = getMessageAuthor(mid);
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("mid", mid)
- .addValue("uid", uid)
- .addValue("rid", rid);
- boolean result;
- if (author.getUid() == uid) {
- result = getNamedParameterJdbcTemplate()
- .update("DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid", sqlParameterSource) > 0;
- } else {
- result = getNamedParameterJdbcTemplate()
- .update("DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid AND user_id=:uid"
- , sqlParameterSource) > 0;
- }
- if (result) {
- getNamedParameterJdbcTemplate().update("UPDATE messages SET replies=replies-1 WHERE message_id=:mid", sqlParameterSource);
- updateRepliesBy(mid);
- return true;
- }
- return false;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getLastMessages(int hours) {
- return getJdbcTemplate().queryForList("SELECT message_id FROM messages WHERE messages.ts>TIMESTAMPADD(HOUR,?,NOW())",
- Integer.class, -hours);
-
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<ResponseReply> getLastReplies(int hours) {
- return getJdbcTemplate().query("SELECT users2.nick,replies.message_id,replies.reply_id," +
- "users.nick,replies.txt," +
- "replies.ts,replies.attach,replies.ts+0, replies.html " +
- "FROM ((replies INNER JOIN users ON replies.user_id=users.id) " +
- "INNER JOIN messages ON replies.message_id=messages.message_id) " +
- "INNER JOIN users AS users2 ON messages.user_id=users2.id " +
- "WHERE replies.ts>TIMESTAMPADD(HOUR,?,NOW()) AND messages.privacy>0", (rs, rowNum) -> {
- ResponseReply reply = new ResponseReply();
- reply.setMuname(rs.getString(1));
- reply.setMid(rs.getInt(2));
- reply.setRid(rs.getInt(3));
- reply.setUname(rs.getString(4));
- reply.setDescription(rs.getString(5));
- reply.setPubDate(rs.getTimestamp(6));
- reply.setAttachmentType(rs.getString(7));
- reply.setHtml(rs.getBoolean(8));
- return reply;
- }, -hours);
- }
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getPopularCandidates() {
- return getJdbcTemplate().queryForList("SELECT replies.message_id FROM replies " +
- "INNER JOIN messages ON replies.message_id = messages.message_id " +
- "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " +
- "WHERE COALESCE(messages_tags.tag_id, 0) != 2 " +
- "AND COALESCE(messages_tags.tag_id, 0) != 805 AND replies.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " +
- "AND messages.popular=0 GROUP BY messages.message_id having COUNT(DISTINCT(replies.user_id)) > 5 " +
- "UNION ALL SELECT favorites.message_id FROM favorites " +
- "INNER JOIN messages ON messages.message_id = favorites.message_id " +
- "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " +
- "WHERE COALESCE(messages_tags.tag_id, 0) != 2 AND favorites.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " +
- "AND messages.popular=0 GROUP BY messages.message_id HAVING COUNT(DISTINCT favorites.user_id) > 1;", Integer.class);
- }
- @Transactional
- @Override
- public void setLastReadComment(User user, Integer mid, Integer rid) {
- jdbcTemplate.update("UPDATE subscr_messages SET last_read_rid=GREATEST(?, last_read_rid) WHERE message_id=? AND suser_id=?",
- rid, mid, user.getUid());
- }
- @Transactional
- @Override
- public void setRead(User user, Integer mid) {
- jdbcTemplate.update("UPDATE subscr_messages SET last_read_rid=(select replies from messages " +
- "where messages.message_id=subscr_messages.message_id) WHERE message_id=? AND suser_id=?",
- mid, user.getUid());
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getUnread(User user) {
- return jdbcTemplate.queryForList(
- "select subscr_messages.message_id " +
- "from subscr_messages inner join messages on subscr_messages.message_id=messages.message_id " +
- "where subscr_messages.suser_id=? and " +
- "messages.replies>subscr_messages.last_read_rid",
- Integer.class, user.getUid());
- }
-
- @Transactional
- @Override
- public boolean updateMessage(Integer mid, Integer rid, String body) {
- Instant now = Instant.now();
- if (rid == 0) {
- return jdbcTemplate.update("UPDATE messages_txt SET txt=?, updated_at=? WHERE message_id=?", body, Timestamp.from(now), mid) > 0;
- } else {
- return jdbcTemplate.update("UPDATE replies SET txt=?, updated_at=? WHERE message_id=? and reply_id=?",
- body, Timestamp.from(now), mid, rid) > 0;
- }
- }
-
- @Override
- public boolean updateReplyUri(Message reply, URI replyUri) {
- return jdbcTemplate.update("UPDATE replies SET reply_uri=?, html=1 WHERE message_id=? AND reply_id=?",
- replyUri.toASCIIString(), reply.getMid(), reply.getRid()) > 0;
- }
-
- @Override
- public boolean replyExists(URI replyUri) {
- return jdbcTemplate.queryForList("SELECT reply_id FROM replies WHERE reply_uri=?",
- Integer.class, replyUri.toASCIIString()).size() > 0;
- }
-
- @Override
- public boolean deleteReply(URI userUri, URI replyUri) {
- return jdbcTemplate.update("DELETE FROM replies WHERE user_uri=? AND reply_uri=?",
- userUri.toASCIIString(), replyUri.toASCIIString()) > 0;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/MessengerServiceImpl.java b/juick-server/src/main/java/com/juick/service/MessengerServiceImpl.java
deleted file mode 100644
index 57101ffe..00000000
--- a/juick-server/src/main/java/com/juick/service/MessengerServiceImpl.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.juick.service;
-
-import com.juick.User;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
-
-@Repository
-public class MessengerServiceImpl extends BaseJdbcService implements MessengerService {
-
- @Transactional(readOnly = true)
- @Override
- public Integer getUserId(String senderId) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT id FROM users INNER JOIN messenger " +
- "ON messenger.user_id = users.id WHERE messenger.sender_id=?", Integer.class, senderId);
-
- return list.isEmpty() ? 0 : list.get(0);
- }
- @Transactional(readOnly = true)
- @Override
- public Optional<String> getSenderId(User user) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT sender_id FROM messenger " +
- "WHERE user_id=?", String.class, user.getUid());
-
- return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0));
- }
-
- @Transactional
- @Override
- public boolean createMessengerUser(String senderId, String displayName) {
- return getJdbcTemplate().update(
- "INSERT INTO messenger(sender_id, display_name, loginhash) VALUES(?,?,?)",
- senderId, displayName, UUID.randomUUID().toString()) > 0;
- }
- @Transactional(readOnly = true)
- @Override
- public String getDisplayName(String hash) {
- try {
- return getJdbcTemplate().queryForObject("SELECT display_name FROM messenger WHERE loginhash=?", String.class, hash);
- } catch (EmptyResultDataAccessException e) {
- return null;
- }
- }
- @Transactional
- @Override
- public String getSignUpHash(final String senderId, final String username) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT loginhash FROM messenger WHERE sender_id = ? AND user_id IS NULL",
- String.class,
- senderId);
-
- if (list.isEmpty()) {
- String hash = UUID.randomUUID().toString();
- getJdbcTemplate().update(
- "INSERT INTO messenger(sender_id, loginhash, display_name) VALUES (?, ?, ?)", senderId, hash, username);
- return hash;
- }
- return list.get(0);
- }
- @Transactional
- @Override
- public boolean linkMessengerUser(String hash, int uid) {
- return getJdbcTemplate().update("UPDATE messenger SET user_id=?, loginhash=NULL WHERE loginhash=?", uid, hash) > 0;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/PMQueriesServiceImpl.java b/juick-server/src/main/java/com/juick/service/PMQueriesServiceImpl.java
deleted file mode 100644
index 712e4b0e..00000000
--- a/juick-server/src/main/java/com/juick/service/PMQueriesServiceImpl.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.Chat;
-import com.juick.User;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.jdbc.core.namedparam.SqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class PMQueriesServiceImpl extends BaseJdbcService implements PMQueriesService {
-
- @Transactional
- @Override
- public boolean createPM(final int uidFrom, final int uid_to, final String body) {
- return getJdbcTemplate().update(
- "INSERT INTO pm(user_id, user_id_to, txt) VALUES (?, ?, ?)",
- uidFrom, uid_to, body) > 0;
- }
-
- @Transactional
- @Override
- public boolean addPMinRoster(final int uid, final String jid) {
- return getJdbcTemplate().update(
- "INSERT INTO pm_inroster(user_id, jid) VALUES (?, ?) ON DUPLICATE KEY UPDATE user_id=user_id", uid, jid) > 0;
- }
-
- @Transactional
- @Override
- public boolean removePMinRoster(final int uid, final String jid) {
- return getJdbcTemplate().update(
- "DELETE FROM pm_inroster WHERE user_id = ? AND jid = ?", uid, jid) > 0;
- }
-
- @Transactional
- @Override
- public boolean havePMinRoster(final int uid, final String jid) {
- List<Integer> res = getJdbcTemplate().queryForList(
- "SELECT 1 FROM pm_inroster WHERE user_id = ? AND jid = ?",
- Integer.class,
- uid, jid);
- return res.size() > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Chat> getLastChats(final User user) {
- return getJdbcTemplate().query(
- "SELECT l.user_id, users.nick, l.last, pm.txt FROM pm "
- + "INNER JOIN users ON users.id = pm.user_id "
- + ""
- + "INNER JOIN (SELECT user_id, MAX(ts) AS last FROM pm "
- + "WHERE user_id_to=? GROUP BY user_id) l ON l.last = pm.ts "
- + "WHERE pm.user_id_to=? "
- + "ORDER BY l.last DESC",
- (rs, rowNum) -> {
- com.juick.Chat u = new com.juick.Chat();
- u.setUid(rs.getInt(1));
- u.setName(rs.getString(2));
- u.setLastMessageTimestamp(rs.getTimestamp(3).toInstant());
- u.setLastMessageText(rs.getString(4).trim());
- return u;
- },
- user.getUid(), user.getUid());
- }
-
- @Transactional
- @Override
- public List<com.juick.Message> getPMMessages(final int uid, final int uidTo) {
- SqlParameterSource sqlParameterSource = new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("uidTo", uidTo);
-
- return getNamedParameterJdbcTemplate().query(
- "SELECT pm.user_id, pm.txt, pm.ts, users.nick FROM pm INNER JOIN users ON users.id=pm.user_id WHERE (user_id = :uid AND user_id_to = :uidTo) "
- + "OR (user_id_to = :uid AND user_id = :uidTo) ORDER BY ts DESC LIMIT 20",
- sqlParameterSource,
- (rs, rowNum) -> {
- com.juick.Message msg = new com.juick.Message();
- int uuid = rs.getInt(1);
- User user = new User();
- user.setUid(uuid);
- user.setName(rs.getString(4));
- msg.setUser(user);
- msg.setText(rs.getString(2).trim());
- msg.setTimestamp(rs.getTimestamp(3).toInstant());
- return msg;
- });
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<com.juick.Message> getLastPMInbox(final int uid) {
- return getJdbcTemplate().query(
- "SELECT pm.user_id, users.nick, pm.txt, pm.ts " +
- "FROM pm INNER JOIN users ON pm.user_id=users.id WHERE pm.user_id_to=? ORDER BY pm.ts DESC LIMIT 20",
- (rs, num) -> {
- com.juick.Message msg = new com.juick.Message();
- msg.setUser(new User());
- msg.getUser().setUid(rs.getInt(1));
- msg.getUser().setName(rs.getString(2));
- msg.setText(rs.getString(3).trim());
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
- return msg;
- },
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<com.juick.Message> getLastPMSent(final int uid) {
- return getJdbcTemplate().query(
- "SELECT pm.user_id_to, users.nick, pm.txt, " +
- "pm.ts FROM pm INNER JOIN users ON pm.user_id_to=users.id " +
- "WHERE pm.user_id=? ORDER BY pm.ts DESC LIMIT 20",
- (rs, num) -> {
- com.juick.Message msg = new com.juick.Message();
- msg.setUser(new User());
- msg.getUser().setUid(rs.getInt(1));
- msg.getUser().setName(rs.getString(2));
- msg.setText(rs.getString(3).trim());
- msg.setTimestamp(rs.getTimestamp(4).toInstant());
- return msg;
- },
- uid);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/PrivacyQueriesServiceImpl.java b/juick-server/src/main/java/com/juick/service/PrivacyQueriesServiceImpl.java
deleted file mode 100644
index 9f9cda1d..00000000
--- a/juick-server/src/main/java/com/juick/service/PrivacyQueriesServiceImpl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.Tag;
-import com.juick.User;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-@Transactional
-public class PrivacyQueriesServiceImpl extends BaseJdbcService implements PrivacyQueriesService {
-
- @Override
- public PrivacyResult blacklistUser(final User user, final User target) {
- int result = getJdbcTemplate().update(
- "DELETE FROM bl_users WHERE user_id = ? AND bl_user_id = ?",
- user.getUid(), target.getUid());
-
- if (result > 0)
- return PrivacyResult.Removed;
-
- getJdbcTemplate().update(
- "INSERT INTO bl_users(user_id, bl_user_id) VALUES (?, ?)",
- user.getUid(), target.getUid());
-
- return PrivacyResult.Added;
- }
-
- @Override
- public PrivacyResult blacklistTag(final User user, final Tag tag) {
- int result = getJdbcTemplate().update(
- "DELETE FROM bl_tags WHERE user_id = ? AND tag_id = ?",
- user.getUid(), tag.TID);
-
- if (result > 0)
- return PrivacyResult.Removed;
-
- getJdbcTemplate().update(
- "INSERT INTO bl_tags(user_id, tag_id) VALUES (?, ?)",
- user.getUid(), tag.TID);
-
- return PrivacyResult.Added;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/PushQueriesServiceImpl.java b/juick-server/src/main/java/com/juick/service/PushQueriesServiceImpl.java
deleted file mode 100644
index 7f97956c..00000000
--- a/juick-server/src/main/java/com/juick/service/PushQueriesServiceImpl.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.springframework.dao.DuplicateKeyException;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.inject.Inject;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class PushQueriesServiceImpl extends BaseJdbcService implements PushQueriesService {
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getGCMRegID(final int uid) {
- return getJdbcTemplate().queryForList(
- "SELECT regid FROM android WHERE user_id=?",
- String.class,
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getGCMTokens(final Collection<Integer> uids) {
- if (CollectionUtils.isEmpty(uids))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT regid FROM android INNER JOIN users ON (users.id = android.user_id) WHERE users.id IN (:ids)",
- new MapSqlParameterSource("ids", uids),
- String.class);
- }
-
- @Transactional
- @Override
- public boolean addGCMToken(Integer uid, String token) {
- return getJdbcTemplate().update("INSERT IGNORE INTO android(user_id,regid) VALUES (?, ?)",
- uid, token) > 0;
- }
-
- @Transactional
- @Override
- public boolean deleteGCMToken(String token) {
- return getJdbcTemplate().update("DELETE FROM android WHERE regid=?", token) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getMPNSURL(final int uid) {
- return getJdbcTemplate().queryForList(
- "SELECT url FROM winphone WHERE user_id=?",
- String.class,
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getMPNSTokens(final Collection<Integer> uids) {
- if (CollectionUtils.isEmpty(uids))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT url FROM winphone INNER JOIN users ON (users.id=winphone.user_id) WHERE users.id IN (:ids)",
- new MapSqlParameterSource("ids", uids),
- String.class);
- }
-
- @Transactional
- @Override
- public boolean addMPNSToken(Integer uid, String token) {
- return getJdbcTemplate().update("INSERT IGNORE INTO winphone(user_id,url) VALUES (?, ?)",
- uid, token) > 0;
- }
-
- @Transactional
- @Override
- public boolean deleteMPNSToken(String token) {
- return getJdbcTemplate().update("DELETE FROM winphone WHERE url=?", token) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getAPNSToken(final int uid) {
- return getJdbcTemplate().queryForList(
- "SELECT token from ios WHERE user_id=?",
- String.class,
- uid);
- }
-
- @Transactional
- @Override
- public boolean deleteAPNSToken(String token) {
- return getJdbcTemplate().update("DELETE FROM ios WHERE token=?", token) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getAPNSTokens(final Collection<Integer> uids) {
- if (CollectionUtils.isEmpty(uids))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT token FROM ios INNER JOIN users ON (users.id = ios.user_id) WHERE users.id IN (:ids)",
- new MapSqlParameterSource("ids", uids),
- String.class);
- }
-
- @Transactional
- @Override
- public boolean addAPNSToken(Integer uid, String token) {
- try {
- return getJdbcTemplate().update("INSERT INTO ios(user_id,token) VALUES (?, ?)",
- uid, token) > 0;
- } catch (DuplicateKeyException e) {
- return true;
- }
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/ShowQueriesServiceImpl.java b/juick-server/src/main/java/com/juick/service/ShowQueriesServiceImpl.java
deleted file mode 100644
index 0fba35f1..00000000
--- a/juick-server/src/main/java/com/juick/service/ShowQueriesServiceImpl.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.User;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-@Transactional(readOnly = true)
-public class ShowQueriesServiceImpl extends BaseJdbcService implements ShowQueriesService {
-
- @Override
- public List<String> getRecommendedUsers(final User forUser) {
- if (forUser == null)
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT u.nick FROM subscr_users su1 INNER JOIN users u " +
- "ON su1.user_id = u.id " +
- "WHERE NOT EXISTS (SELECT 1 FROM subscr_users su2 WHERE su2.suser_id = :uid and su1.user_id = su2.user_id) " +
- "AND EXISTS (SELECT 1 FROM subscr_users su3 WHERE su3.suser_id = :uid and su3.user_id = su1.suser_id ) " +
- "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and su1.user_id = b.bl_user_id) " +
- "AND su1.user_id != :uid AND u.lastmessage > UNIX_TIMESTAMP() - 259200 " +
- "GROUP BY su1.user_id ORDER BY count(*) DESC LIMIT 10",
- new MapSqlParameterSource("uid", forUser.getUid()),
- String.class);
- }
-
- @Override
- public List<String> getTopUsers() {
- return getJdbcTemplate().query(
- "SELECT users.nick,COUNT(subscr_users.suser_id) AS cnt " +
- "FROM (subscr_users INNER JOIN users ON subscr_users.user_id=users.id) " +
- "INNER JOIN useroptions ON users.id=useroptions.user_id " +
- "WHERE useroptions.privacy_view>0 AND users.lastmessage > UNIX_TIMESTAMP() - 259200 " +
- "AND users.id!=2 GROUP BY subscr_users.user_id ORDER BY cnt DESC LIMIT 10",
- (rs, rowNum) -> rs.getString(1));
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/SphinxSearchService.java b/juick-server/src/main/java/com/juick/service/SphinxSearchService.java
deleted file mode 100644
index de7bd7f2..00000000
--- a/juick-server/src/main/java/com/juick/service/SphinxSearchService.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.User;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.inject.Inject;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Created by aalexeev on 11/18/16.
- */
-
-@Repository
-@Transactional(readOnly = true)
-public class SphinxSearchService extends BaseJdbcService implements SearchService {
- private static final int DEFAULT_MAX_RESULT = 20;
-
- private int maxResult = DEFAULT_MAX_RESULT;
-
- @Inject
- UserService userService;
-
- public String sortHint(String searchString) {
- boolean isOneWord = searchString.split("[^\\S\\+]+").length == 1;
- return isOneWord ? "extended:@id desc" : "extended:@weight desc, @id desc";
- }
-
- @Override
- public List<Integer> searchInAllMessages(User visitor, final String searchString, final int page) {
- if (StringUtils.isBlank(searchString))
- return Collections.emptyList();
-
- Map<String, String> sphinxQuery = new HashMap<>();
- sphinxQuery.put("limit", String.valueOf(maxResult));
- sphinxQuery.put("mode", "any");
- sphinxQuery.put("sort", sortHint(searchString));
- String usersFilter = userService.getUserBLUsers(visitor.getUid()).stream().map(u -> String.valueOf(u.getUid())).collect(Collectors.joining(","));
- sphinxQuery.put("!filter", "user_id," + usersFilter);
- if (page > 0) {
- sphinxQuery.put("offset", String.valueOf(page * maxResult));
- }
-
- return getJdbcTemplate().queryForList(
- String.format("SELECT id FROM search WHERE query = '%s;%s'", searchString,
- sphinxQuery.entrySet().stream().map(Object::toString)
- .collect(Collectors.joining(";"))), Integer.class);
- }
-
- @Override
- public List<Integer> searchByStringAndUser(User visitor, final String searchString, final int userId, int page) {
- if (StringUtils.isBlank(searchString))
- return Collections.emptyList();
-
- Map<String, String> sphinxQuery = new HashMap<>();
- sphinxQuery.put("limit", String.valueOf(maxResult));
- sphinxQuery.put("mode", "any");
- sphinxQuery.put("sort", sortHint(searchString));
- if (page > 0) {
- sphinxQuery.put("offset", String.valueOf(page * maxResult));
- }
- return getJdbcTemplate().queryForList(
- String.format("SELECT id FROM search WHERE query = '%s;%s;filter=user_id,%d'", searchString,
- sphinxQuery.entrySet().stream().map(Object::toString)
- .collect(Collectors.joining(";")), userId), Integer.class);
- }
-
- @Override
- public void setMaxResult(int maxResult) {
- if (maxResult <= 0)
- throw new IllegalArgumentException("maxResult value (" + maxResult + ") must be greater then 0");
-
- this.maxResult = maxResult;
- }
-} \ No newline at end of file
diff --git a/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java b/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
deleted file mode 100644
index 5ce3593b..00000000
--- a/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.Message;
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.model.NotifyOpts;
-import com.juick.util.MessageUtils;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IteratorUtils;
-import org.apache.commons.collections4.ListUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.dao.DuplicateKeyException;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Nonnull;
-import javax.inject.Inject;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class SubscriptionServiceImpl extends BaseJdbcService implements SubscriptionService {
- @Inject
- private UserService userService;
- @Inject
- private MessagesService messagesService;
- @Inject
- private TagService tagService;
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getSubscribedUsers(final int uid, final Message msg) {
- int mid = msg.getMid();
- User author = messagesService.getMessageAuthor(mid);
-
- List<User> subscribers = userService.getUserReaders(uid);
- List<User> mentionedUsers = userService.getUsersByName(MessageUtils.getMentions(msg).stream()
- .map(u -> u.substring(1)).collect(Collectors.toList()));
- List<User> users = ListUtils.union(subscribers, mentionedUsers);
- List<Integer> tags = tagService.getMessageTagsIDs(mid);
- List<String> tagsStr = tagService.getMessageTags(mid).stream().map(t -> t.getTag().getName()).collect(Collectors.toList());
-
- Set<Integer> set = new HashSet<>();
- set.addAll(
- users.stream()
- .map(User::getUid).filter(u -> Collections.disjoint(tagService.getUserBLTags(u), tagsStr))
- .collect(Collectors.toList()));
-
-
- if (!tags.isEmpty()) {
- List<Integer> tagUsers = getNamedParameterJdbcTemplate().queryForList(
- "SELECT st.suser_id FROM subscr_tags st " +
- "WHERE st.tag_id IN (:ids) AND st.suser_id != :uid " +
- " AND NOT EXISTS (SELECT 1 FROM bl_users bu WHERE bu.bl_user_id = :authorUid and st.suser_id = bu.user_id)" +
- " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN (:ids) and st.suser_id = bt.user_id)",
- new MapSqlParameterSource()
- .addValue("ids", tags)
- .addValue("uid", uid)
- .addValue("authorUid", author.getUid()),
- Integer.class);
- set.addAll(tagUsers);
- }
- return userService.getUsersByID(set);
- }
- @Override
- public List<User> getUsersSubscribedToComments(@Nonnull final Message msg, @Nonnull final Message reply) {
- return getUsersSubscribedToComments(msg, reply, false);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getUsersSubscribedToComments(@Nonnull final Message msg, @Nonnull final Message reply,
- boolean blacklisted) {
- List<User> subscribers = userService.getUsersByID(getJdbcTemplate().queryForList(
- "SELECT suser_id FROM subscr_messages WHERE message_id=? AND suser_id!=?",
- Integer.class,
- msg.getMid(), reply.getUser().getUid()));
- List<User> mentionedUsers = userService.getUsersByName(MessageUtils.getMentions(reply).stream()
- .map(u -> u.substring(1)).collect(Collectors.toList()));
- List<User> users = IteratorUtils.toList(CollectionUtils.union(subscribers, mentionedUsers).iterator());
- if (!users.isEmpty()) {
- return users.stream()
- .filter(u -> blacklisted || !userService.isReplyToBL(u, reply))
- .collect(Collectors.toList());
- }
- return Collections.emptyList();
- }
-
- @Override
- public List<User> getUsersSubscribedToUserRecommendations(final int uid, final Message msg) {
- List<String> msgTags = tagService.getMessageTags(msg.getMid()).stream().map(t -> t.getTag().getName()).collect(Collectors.toList());
- if (msg.getLikes() == 1) {
- return userService.getUserReaders(uid).stream()
- .filter(u -> !u.equals(msg.getUser()))
- .filter(u -> !userService.isInBLAny(u.getUid(), msg.getUser().getUid()))
- .filter(u -> Collections.disjoint(tagService.getUserBLTags(u.getUid()), msgTags))
- .collect(Collectors.toList());
- }
- return Collections.emptyList();
- }
-
- @Transactional
- @Override
- public boolean subscribeMessage(final Message message, final User user) {
- try {
- boolean result = getJdbcTemplate().update(
- "INSERT INTO subscr_messages(suser_id, message_id) VALUES (?, ?)", user.getUid(), message.getMid()) == 1;
- messagesService.setLastReadComment(user, message.getMid(), message.getReplies());
- return result;
- } catch (DuplicateKeyException e) {
- return true;
- }
- }
-
- @Transactional
- @Override
- public boolean unSubscribeMessage(final int mid, final int vuid) {
- return getJdbcTemplate().update(
- "DELETE FROM subscr_messages WHERE message_id=? AND suser_id=?", mid, vuid) > 0;
- }
-
- @Transactional
- @Override
- public boolean subscribeUser(final User user, final User toUser) {
- try {
- return getJdbcTemplate().update(
- "INSERT INTO subscr_users(user_id,suser_id) VALUES (?,?)", toUser.getUid(), user.getUid()) == 1;
- } catch (DuplicateKeyException e) {
- return true;
- }
- }
-
- @Transactional
- @Override
- public boolean unSubscribeUser(final User user, final User fromUser) {
- return getJdbcTemplate().update(
- "DELETE FROM subscr_users WHERE suser_id=? AND user_id=?", user.getUid(), fromUser.getUid()) > 0;
- }
-
- @Transactional
- @Override
- public boolean subscribeTag(final User user, final Tag toTag) {
- try {
-
- return getJdbcTemplate().update(
- "INSERT INTO subscr_tags(tag_id,suser_id) VALUES (?,?)", toTag.TID, user.getUid()) == 1;
- } catch (DuplicateKeyException e) {
- return true;
- }
- }
-
- @Transactional
- @Override
- public boolean unSubscribeTag(final User user, final Tag toTag) {
- return getJdbcTemplate().update(
- "DELETE FROM subscr_tags WHERE tag_id=? AND suser_id=?", toTag.TID, user.getUid()) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getSubscribedTags(User user) {
- return getJdbcTemplate().queryForList("SELECT tags.name FROM subscr_tags INNER JOIN tags " +
- "ON(tags.tag_id = subscr_tags.tag_id) " +
- "WHERE subscr_tags.suser_id=? ORDER BY tags.name", String.class, user.getUid());
- }
-
- @Transactional(readOnly = true)
- @Override
- public NotifyOpts getNotifyOptions(final User user) {
- List<NotifyOpts> list = getJdbcTemplate().query(
- "SELECT jnotify,subscr_notify,recommendations FROM useroptions WHERE user_id=?",
- (rs, num) -> {
- NotifyOpts options = new NotifyOpts();
- options.setRepliesEnabled(rs.getInt(1) > 0);
- options.setSubscriptionsEnabled(rs.getInt(2) > 0);
- options.setRecommendationsEnabled(rs.getInt(3) > 0);
- return options;
- },
- user.getUid());
-
- return list.isEmpty() ?
- new NotifyOpts() : list.get(0);
- }
-
- @Transactional
- @Override
- public boolean setNotifyOptions(final User user, final NotifyOpts options) {
- int jnotify = getJdbcTemplate().update(
- "UPDATE useroptions SET jnotify=? WHERE user_id=?",
- options.isRepliesEnabled() ? 1 : 0,
- user.getUid());
-
- int subscr_notify = getJdbcTemplate().update(
- "UPDATE useroptions SET subscr_notify=? WHERE user_id=?",
- options.isSubscriptionsEnabled() ? 1 : 0,
- user.getUid());
-
- int recommendations = getJdbcTemplate().update(
- "UPDATE useroptions SET recommendations=? WHERE user_id=?",
- options.isRecommendationsEnabled() ? 1 : 0,
- user.getUid());
-
- return jnotify > 0 && subscr_notify > 0 && recommendations > 0;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/TagServiceImpl.java b/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
deleted file mode 100644
index 42159d3b..00000000
--- a/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.Tag;
-import com.juick.User;
-import com.juick.model.TagStats;
-import com.juick.util.StreamUtils;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class TagServiceImpl extends BaseJdbcService implements TagService {
-
- @Transactional(readOnly = true)
- @Override
- public com.juick.Tag getTag(final int tid) {
- List<Tag> list = getJdbcTemplate().query(
- "SELECT synonym_id,name FROM tags WHERE tag_id=?",
- (rs, num) -> {
- Tag ret = new Tag(rs.getString(2));
- ret.TID = tid;
- ret.SynonymID = rs.getInt(1);
- return ret;
- },
- tid);
-
- return list.isEmpty() ?
- null : list.get(0);
- }
-
- @Transactional
- @Override
- public com.juick.Tag getTag(final String tag, final boolean autoCreate) {
- if (StringUtils.isBlank(tag))
- return null;
-
- List<Tag> list = getJdbcTemplate().query(
- "SELECT tag_id, synonym_id, name FROM tags WHERE name = ?",
- (rs, rowNum) -> {
- Tag ret1 = new Tag(rs.getString(3));
- ret1.TID = rs.getInt(1);
- ret1.SynonymID = rs.getInt(2);
- return ret1;
- },
- tag);
-
- Tag ret = list.isEmpty() ?
- null : list.get(0);
-
- if (ret == null && autoCreate) {
- ret = new com.juick.Tag(tag);
- ret.TID = createTag(tag);
- }
-
- return ret;
- }
-
- @Override
- public List<Tag> getTags(Stream<String> tags, final boolean autoCreate) {
- return tags.filter(StringUtils::isNotBlank).map(tag -> getTag(tag, autoCreate)).filter(Objects::nonNull).distinct()
- .collect(Collectors.toList());
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean getTagNoIndex(final int tagId) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT noindex FROM tags WHERE tag_id=?", Integer.class, tagId);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional
- @Override
- public int createTag(final String name) {
- KeyHolder holder = new GeneratedKeyHolder();
- getJdbcTemplate().update(
- con -> {
- PreparedStatement stmt = con.prepareStatement(
- "INSERT INTO tags(name) VALUES (?)",
- Statement.RETURN_GENERATED_KEYS);
- stmt.setString(1, name);
- return stmt;
- },
- holder);
-
- return holder.getKey().intValue();
- }
-
- private class TagStatsMapper implements RowMapper<TagStats> {
-
- @Override
- public TagStats mapRow(ResultSet rs, int rowNum) throws SQLException {
- Tag t = new Tag(rs.getString(1));
- TagStats s = new TagStats();
- s.setTag(t);
- s.setUsageCount(rs.getInt(2));
- return s;
- }
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<TagStats> getUserTagStats(final int uid) {
- return getJdbcTemplate().query(
- "SELECT tags.name,COUNT(messages.message_id) " +
- "FROM (messages INNER JOIN messages_tags ON (messages.user_id=? " +
- "AND messages.message_id=messages_tags.message_id)) " +
- "INNER JOIN tags ON messages_tags.tag_id=tags.tag_id GROUP BY tags.tag_id ORDER BY tags.name ASC",
- new TagStatsMapper(),
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getUserBLTags(final int uid) {
- return getJdbcTemplate().queryForList(
- "SELECT tags.name FROM tags INNER JOIN bl_tags " +
- "ON (bl_tags.user_id = ? AND bl_tags.tag_id = tags.tag_id) ORDER BY tags.name",
- String.class, uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getPopularTags() {
- return getJdbcTemplate().queryForList(
- "select name from tags where noindex=0 order by stat_messages desc limit 20", String.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<TagStats> getTagStats() {
- return getJdbcTemplate().query(
- "SELECT tags.name,COUNT(DISTINCT messages.user_id) AS cnt " +
- "FROM (messages INNER JOIN messages_tags ON (messages.ts>TIMESTAMPADD(DAY,-3,NOW()) " +
- "AND messages.message_id=messages_tags.message_id)) " +
- "INNER JOIN tags ON messages_tags.tag_id=tags.tag_id " +
- "WHERE tags.tag_id NOT IN (SELECT tag_id FROM tags_ignore) " +
- "GROUP BY tags.tag_id ORDER BY cnt DESC LIMIT 20", new TagStatsMapper());
- }
-
- @Transactional
- @Override
- public List<Tag> updateTags(final int mid, final Collection<Tag> newTags) {
- List<Tag> currentTags = getMessageTags(mid).stream()
- .map(TagStats::getTag).collect(Collectors.toList());
-
- if (CollectionUtils.isEmpty(newTags))
- return currentTags;
-
- List<Integer> idsForDelete = newTags.stream()
- .filter(currentTags::contains)
- .map(tag -> tag.TID)
- .collect(Collectors.toList());
- if (newTags.size() - idsForDelete.size() >= 5) {
- return currentTags;
- }
-
- if (!idsForDelete.isEmpty())
- getNamedParameterJdbcTemplate().update(
- "DELETE FROM messages_tags WHERE message_id = :mid AND tag_id in (:ids)",
- new MapSqlParameterSource().addValue("ids", idsForDelete).addValue("mid", mid));
-
- newTags.stream().filter(t -> !currentTags.contains(t))
- .forEach(t -> getJdbcTemplate().update("INSERT INTO messages_tags(message_id,tag_id) VALUES (?,?)", mid, t.TID));
-
- List<Tag> result = getMessageTags(mid).stream()
- .map(TagStats::getTag).collect(Collectors.toList());
- jdbcTemplate.update("UPDATE messages_txt SET tags=? WHERE message_id=?", result.stream()
- .map(Tag::getName).collect(Collectors.joining(" ")), mid);
- return result;
- }
-
- @Override
- public Pair<String, List<Tag>> fromString(final String txt) {
- String firstLine = txt.split("\\n", 2)[0];
- Supplier<Stream<String>> tagsStream = () -> StreamUtils.takeWhile(Arrays.stream(firstLine.split("\\ ")),
- t -> !t.equals("*") && t.startsWith("*"));
- int tagsLength = tagsStream.get().collect(Collectors.joining(" ")).length();
- String body = txt.substring(tagsLength);
- List<Tag> tags = tagsStream.get().map(t -> getTag(t.substring(1), true))
- .distinct().collect(Collectors.toList());
- return Pair.of(body, tags);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<TagStats> getMessageTags(final int mid) {
- return getJdbcTemplate().query(
- "SELECT tags.tag_id,synonym_id,name,stat_messages FROM tags " +
- "INNER JOIN messages_tags ON (messages_tags.message_id = ? AND messages_tags.tag_id = tags.tag_id)",
- (rs, num) -> {
- com.juick.Tag t = new com.juick.Tag(rs.getString(3));
- t.TID = rs.getInt(1);
- t.SynonymID = rs.getInt(2);
- TagStats s = new TagStats();
- s.setTag(t);
- s.setUsageCount(rs.getInt(4));
- return s;
- }, mid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getMessageTagsIDs(final int mid) {
- return getJdbcTemplate().queryForList(
- "SELECT tag_id FROM messages_tags WHERE message_id = ?",
- Integer.class, mid);
- }
-
- @Override
- public boolean blacklistTag(User user, Tag tag) {
- int rowcount = getNamedParameterJdbcTemplate().update("DELETE FROM bl_tags WHERE tag_id = :tid AND user_id = :uid",
- new MapSqlParameterSource().addValue("tid", tag.TID).addValue("uid", user.getUid()));
- return rowcount <= 0 && getNamedParameterJdbcTemplate()
- .update("INSERT INTO bl_tags(user_id, tag_id) VALUES(:uid,:tid)",
- new MapSqlParameterSource().addValue("tid", tag.TID)
- .addValue("uid", user.getUid())) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isInBL(User user, Tag tag) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM bl_tags WHERE user_id = ? AND tag_id = ?",
- Integer.class, user.getUid(), tag.TID);
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isSubscribed(User user, Tag tag) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM subscr_tags WHERE suser_id = ? AND tag_id = ?",
- Integer.class, user.getUid(), tag.TID);
- return !list.isEmpty() && list.get(0) == 1;
- }
-
-}
diff --git a/juick-server/src/main/java/com/juick/service/TelegramServiceImpl.java b/juick-server/src/main/java/com/juick/service/TelegramServiceImpl.java
deleted file mode 100644
index 99cbabf6..00000000
--- a/juick-server/src/main/java/com/juick/service/TelegramServiceImpl.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.User;
-import org.springframework.dao.DuplicateKeyException;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-/**
- * Created by vt on 24/11/2016.
- */
-@Repository
-public class TelegramServiceImpl extends BaseJdbcService implements TelegramService {
-
- @Transactional
- @Override
- public boolean deleteAnonymous(Long id) {
- return getJdbcTemplate().update("DELETE FROM telegram WHERE tg_id=? AND user_id IS NULL", id) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Long> getAnonymous() {
- return getJdbcTemplate().queryForList("SELECT tg_id FROM telegram WHERE user_id IS NULL", Long.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUser(final long tgId) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT id FROM users INNER JOIN telegram " +
- "ON telegram.user_id = users.id WHERE telegram.tg_id=?", Integer.class, tgId);
-
- return list.isEmpty() ? 0 : list.get(0);
- }
-
- @Transactional
- @Override
- public boolean createTelegramUser(final long tgID, final String tgName) {
- return getJdbcTemplate().update(
- "INSERT INTO telegram(tg_id, tg_name, loginhash) VALUES(?,?,?)",
- tgID, tgName, UUID.randomUUID().toString()) > 0;
- }
-
- @Transactional
- @Override
- public boolean deleteTelegramUser(Integer uid) {
- return getJdbcTemplate().update("DELETE FROM telegram WHERE user_id=?", uid) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Long> getTelegramIdentifiers(List<User> users) {
- List<Integer> uids = users.stream().map(User::getUid).collect(Collectors.toList());
- if (uids.isEmpty()) {
- return Collections.emptyList();
- }
- return getNamedParameterJdbcTemplate().queryForList("" +
- "SELECT tg_id FROM telegram WHERE user_id IN(:uids)", new MapSqlParameterSource()
- .addValue("uids", uids), Long.class);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java b/juick-server/src/main/java/com/juick/service/UserServiceImpl.java
deleted file mode 100644
index fdc4f28c..00000000
--- a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service;
-
-import com.juick.Message;
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import com.juick.model.Auth;
-import com.juick.model.UserInfo;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.dao.DuplicateKeyException;
-import org.springframework.dao.EmptyResultDataAccessException;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Nonnull;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Timestamp;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.UUID;
-
-/**
- * Created by aalexeev on 11/13/16.
- */
-@Repository
-public class UserServiceImpl extends BaseJdbcService implements UserService {
-
- private class UserMapper implements RowMapper<User> {
- @Override
- public User mapRow(ResultSet rs, int rowNum) throws SQLException {
- User user = new User();
-
- user.setUid(rs.getInt(1));
- user.setName(rs.getString(2));
- user.setCredentials(rs.getString(3));
- user.setBanned(rs.getBoolean(4));
- Timestamp seen = rs.getTimestamp(5);
- if (seen != null) {
- user.setSeen(seen.toInstant());
- }
- return user;
- }
- }
-
- @Transactional
- @Override
- public String getSignUpHashByJID(final String jid) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT loginhash FROM jids WHERE jid = ? AND user_id IS NULL", String.class, jid);
-
- if (list.isEmpty()) {
- String hash = UUID.randomUUID().toString();
- getJdbcTemplate().update("INSERT INTO jids(jid, loginhash) VALUES (?, ?)", jid, hash);
- return hash;
- }
- return list.get(0);
- }
-
- @Transactional
- @Override
- public String getSignUpHashByTelegramID(final Long telegramId, final String username) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT loginhash FROM telegram WHERE tg_id = ? AND user_id IS NULL",
- String.class,
- telegramId);
-
- if (list.isEmpty()) {
- String hash = UUID.randomUUID().toString();
- getJdbcTemplate().update(
- "INSERT INTO telegram(tg_id, loginhash, tg_name) VALUES (?, ?, ?)", telegramId, hash, username);
- return hash;
- }
- return list.get(0);
- }
-
- @Transactional
- @Override
- public int createUser(final String username, final String password) {
- KeyHolder holder = new GeneratedKeyHolder();
- try {
- getJdbcTemplate().update(
- con -> {
- PreparedStatement stmt = con.prepareStatement(
- "INSERT INTO users(nick,passw) VALUES (?,?)",
- Statement.RETURN_GENERATED_KEYS);
- stmt.setString(1, username);
- stmt.setString(2, password);
- return stmt;
- },
- holder);
- } catch (DuplicateKeyException e) {
- return -1;
- }
-
- int uid = holder.getKey().intValue();
-
- getJdbcTemplate().update("INSERT INTO useroptions(user_id) VALUES (?)", uid);
- getJdbcTemplate().update("INSERT INTO subscr_users(user_id, suser_id) VALUES (2, ?)", uid);
-
- return uid;
- }
-
- @Transactional(readOnly = true)
- @Override
- public Optional<User> getUserByUID(final int uid) {
- List<User> list = getJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE id = ?", new UserMapper(), uid);
-
- return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0));
- }
-
- @Transactional(readOnly = true)
- @Nonnull
- @Override
- public User getUserByName(final String username) {
- if (StringUtils.isNotBlank(username)) {
- List<User> list = getJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE nick = ?", new UserMapper(), username);
-
- if (!list.isEmpty())
- return list.get(0);
- }
- return AnonymousUser.INSTANCE;
- }
-
- @Override
- @Transactional(readOnly = true)
- @Nonnull
- public User getUserByEmail(String email) {
- if (StringUtils.isNotBlank(email)) {
- List<User> list = getJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE id = (SELECT DISTINCT user_id FROM emails WHERE email = ?)",
- new UserMapper(),
- email);
-
- if (!list.isEmpty())
- return list.get(0);
- }
- return AnonymousUser.INSTANCE;
- }
-
- @Transactional(readOnly = true)
- @Override
- public User getUserByJID(final String jid) {
- User result = null;
-
- if (StringUtils.isNotBlank(jid)) {
- List<User> list = getJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE id = (SELECT user_id FROM jids WHERE jid = ?)",
- new UserMapper(),
- jid);
-
- if (!list.isEmpty())
- result = list.get(0);
- }
- return result;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getUsersByName(final Collection<String> unames) {
- if (CollectionUtils.isEmpty(unames))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE nick IN (:unames)",
- new MapSqlParameterSource("unames", unames),
- new UserMapper());
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getUsersByID(final Collection<Integer> uids) {
- if (CollectionUtils.isEmpty(uids))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE id IN (:ids)",
- new MapSqlParameterSource("ids", uids),
- new UserMapper());
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getJIDsbyUID(final int uid) {
- return getJdbcTemplate().queryForList("SELECT jid FROM jids WHERE user_id = ? AND active = 1", String.class, uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUIDbyJID(final String jid) {
- if (StringUtils.isNotBlank(jid)) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT user_id FROM jids WHERE jid = ?", Integer.class, jid);
-
- if (!list.isEmpty())
- return list.get(0);
- }
- return 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUIDbyName(final String uname) {
- if (StringUtils.isNotBlank(uname)) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT id FROM users WHERE nick = ?", Integer.class, uname);
-
- if (!list.isEmpty())
- return list.get(0);
- }
- return 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUIDbyHash(final String hash) {
- if (StringUtils.isNotBlank(hash)) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT user_id FROM logins WHERE hash = ?", Integer.class, hash);
-
- if (!list.isEmpty())
- return list.get(0);
- }
- return 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public com.juick.User getUserByHash(final String hash) {
- if (StringUtils.isNotBlank(hash)) {
- List<User> list = getJdbcTemplate().query(
- "SELECT logins.user_id, users.nick, users.passw, users.banned, last_seen FROM logins " +
- "INNER JOIN users ON logins.user_id = users.id WHERE logins.hash = ?",
- new UserMapper(),
- hash);
-
- if (!list.isEmpty()) {
- User user = list.get(0);
- user.setAuthHash(hash);
- return user;
- }
- }
- return AnonymousUser.INSTANCE;
- }
-
- @Transactional
- @Override
- public String getHashByUID(final int uid) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT hash FROM logins WHERE user_id = ?", String.class, uid);
-
- if (list.isEmpty()) {
- String hash = RandomStringUtils.randomAlphanumeric(16).toUpperCase();
- getJdbcTemplate().update("INSERT INTO logins(user_id, hash) VALUES (?, ?)", uid, hash);
- return hash;
- }
- return list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int checkPassword(final String username, final String password) {
- if (StringUtils.isNotBlank(username)) {
- List<User> list = getJdbcTemplate().query(
- "SELECT id, nick, passw, banned, last_seen FROM users WHERE nick = ?",
- new UserMapper(),
- username);
-
- if (!list.isEmpty()) {
- User user = list.get(0);
- if (Objects.equals(password, user.getCredentials()))
- return user.getUid();
- }
- }
- return -1;
- }
-
- @Transactional
- @Override
- public boolean updatePassword(final User user, final String newPassword) {
- return user != null &&
- user.getUid() > 0 &&
- getJdbcTemplate().update("UPDATE users SET passw = ? WHERE id = ?", newPassword, user.getUid()) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getUserOptionInt(final int uid, final String option, final int defaultValue) {
- if (StringUtils.isBlank(option))
- return defaultValue;
-
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT " + option + " FROM useroptions WHERE user_id = ?", Integer.class, uid);
-
- return list.isEmpty() ? defaultValue : list.get(0);
- }
-
- @Transactional
- @Override
- public int setUserOptionInt(final int uid, final String option, final int value) {
- if (StringUtils.isBlank(option))
- return 0;
-
- return getJdbcTemplate().update("UPDATE useroptions SET " + option + "= ? WHERE user_id = ?", value, uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public UserInfo getUserInfo(final User user) {
- List<UserInfo> list = getJdbcTemplate().query(
- "SELECT fullname, country, url, descr FROM usersinfo WHERE user_id = ?",
- ((rs, rowNum) -> {
- UserInfo info = new UserInfo();
- info.setFullName(rs.getString(1));
- info.setCountry(rs.getString(2));
- info.setUrl(rs.getString(3));
- info.setDescription(rs.getString(4));
- return info;
- }),
- user.getUid());
-
- return list.isEmpty() ? new UserInfo() : list.get(0);
- }
-
- @Transactional
- @Override
- public boolean updateUserInfo(final User user, final UserInfo info) {
- return getJdbcTemplate().update(
- "INSERT INTO usersinfo(user_id, fullname, country, url, descr) VALUES (?, ?, ?, ?, ?) " +
- "ON DUPLICATE KEY UPDATE fullname = ?, country = ?, url = ?, descr = ?",
- user.getUid(),
- info.getFullName(),
- info.getCountry(),
- info.getUrl(),
- info.getDescription(),
- info.getFullName(),
- info.getCountry(),
- info.getUrl(),
- info.getDescription()) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean getCanMedia(final int uid) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT users.lastphoto - UNIX_TIMESTAMP() FROM users WHERE id = ?",
- Integer.class,
- uid);
-
- return !list.isEmpty() && list.get(0) < 3600;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isInWL(final int uid, final int check) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM wl_users WHERE user_id = ? AND wl_user_id = ?",
- Integer.class, uid, check);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isInBL(final int uid, final int check) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM bl_users WHERE user_id = ? AND bl_user_id = ?", Integer.class, uid, check);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isInBLAny(final int uid, final int uid2) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM bl_users WHERE (user_id = ? AND bl_user_id = ?) "
- + "OR (user_id = ? AND bl_user_id = ?)",
- new Object[]{uid, uid2, uid2, uid},
- Integer.class);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isReplyToBL(final User user, final Message reply) {
- return getNamedParameterJdbcTemplate().queryForObject("WITH RECURSIVE banned(reply_id, user_id) AS (" +
- "SELECT reply_id, user_id FROM replies " +
- "WHERE replies.message_id = :mid " +
- "AND EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " +
- "UNION ALL SELECT replies.reply_id, replies.user_id FROM replies " +
- "INNER JOIN banned ON banned.reply_id = replies.replyto " +
- "WHERE replies.message_id = :mid) " +
- "SELECT COUNT(reply_id) from replies " +
- "INNER JOIN messages m ON m.message_id = replies.message_id " +
- "WHERE replies.message_id = :mid " +
- "AND replies.reply_id = :rid " +
- "AND (EXISTS (SELECT 1 FROM banned WHERE banned.reply_id = replies.reply_id) " +
- "OR EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = m.user_id)" +
- "OR EXISTS (SELECT 1 FROM bl_users b WHERE b.bl_user_id = :uid AND b.user_id = m.user_id))",
- new MapSqlParameterSource("uid", user.getUid())
- .addValue("mid", reply.getMid())
- .addValue("rid", reply.getRid()),
- Integer.class) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> checkBL(final int visitor, final Collection<Integer> uids) {
- if (CollectionUtils.isEmpty(uids))
- return Collections.emptyList();
-
- return getNamedParameterJdbcTemplate().queryForList(
- "SELECT user_id FROM bl_users WHERE bl_user_id = :visitor and user_id IN (:ids)",
- new MapSqlParameterSource()
- .addValue("visitor", visitor)
- .addValue("ids", uids),
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
- public boolean isSubscribed(final int uid, final int check) {
- List<Integer> list = getJdbcTemplate().queryForList(
- "SELECT 1 FROM subscr_users WHERE suser_id = ? AND user_id = ?",
- Integer.class, uid, check);
-
- return !list.isEmpty() && list.get(0) == 1;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<com.juick.User> getUserReadLeastPopular(final int uid, final int cnt) {
- return getJdbcTemplate().query(
- "SELECT users.id,users.nick FROM (subscr_users " +
- "INNER JOIN users_subscr ON (subscr_users.suser_id=? " +
- "AND subscr_users.user_id=users_subscr.user_id)) INNER JOIN users " +
- "ON subscr_users.user_id=users.id ORDER BY cnt LIMIT ?",
- (rs, num) -> {
- com.juick.User u = new com.juick.User();
- u.setUid(rs.getInt(1));
- u.setName(rs.getString(2));
- return u;
- },
- uid,
- cnt);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getUserReaders(final int uid) {
- return getJdbcTemplate().query(
- "SELECT users.id, users.nick FROM subscr_users " +
- "INNER JOIN users ON subscr_users.suser_id=users.id " +
- "WHERE subscr_users.user_id=? ORDER BY users.nick",
- (rs, num) -> {
- com.juick.User u = new com.juick.User();
- u.setUid(rs.getInt(1));
- u.setName(rs.getString(2));
- return u;
- },
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<User> getUserFriends(final int uid) {
- return getJdbcTemplate().query(
- "SELECT users.id,users.nick FROM subscr_users " +
- "INNER JOIN users ON subscr_users.user_id=users.id " +
- "WHERE subscr_users.suser_id=? AND users.id!=? " +
- "ORDER BY users.nick",
- (rs, num) -> {
- com.juick.User u = new com.juick.User();
- u.setUid(rs.getInt(1));
- u.setName(rs.getString(2));
- return u;
- },
- uid,
- uid);
- }
-
- @Transactional(readOnly = true)
- @Override
- public Integer getUserRecommendations(User user) {
- try {
- return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM favorites WHERE user_id=?", Integer.class, user.getUid());
- } catch (EmptyResultDataAccessException e) {
- return 0;
- }
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<com.juick.User> getUserBLUsers(final int uid) {
- return getJdbcTemplate().query("SELECT users.id,users.nick FROM users INNER JOIN bl_users " +
- "ON(bl_users.bl_user_id=users.id) WHERE bl_users.user_id=? ORDER BY users.nick",
- (rs, num) -> {
- com.juick.User u = new com.juick.User();
- u.setUid(rs.getInt(1));
- u.setName(rs.getString(2));
- return u;
- }, uid);
- }
-
- @Transactional
- @Override
- public boolean linkTwitterAccount(
- final User user, final String accessToken, final String accessTokenSecret, final String screenName) {
- return getJdbcTemplate().update("INSERT INTO twitter(user_id,access_token,access_token_secret,uname) " +
- "VALUES (?,?,?,?)" +
- " ON DUPLICATE KEY UPDATE access_token=?,access_token_secret=?,uname=?",
- user.getUid(), accessToken, accessTokenSecret, screenName, accessToken, accessTokenSecret, screenName) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getStatsMyReaders(final int uid) {
- List<Integer> list = getJdbcTemplate().queryForList("SELECT COUNT(*) FROM subscr_users WHERE user_id = ?", Integer.class, uid);
- return list.isEmpty() ? 0 : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getStatsMessages(final int uid) {
- List<Integer> list = getJdbcTemplate().queryForList("SELECT COUNT(*) FROM messages WHERE user_id = ?", Integer.class, uid);
- return list.isEmpty() ? 0 : list.get(0);
- }
-
- @Transactional(readOnly = true)
- @Override
- public int getStatsReplies(final int uid) {
- List<Integer> list = getJdbcTemplate().queryForList("SELECT COUNT(*) FROM replies WHERE user_id = ?", Integer.class, uid);
- return list.isEmpty() ? 0 : list.get(0);
- }
-
- @Transactional
- @Override
- public boolean setActiveStatusForJID(final String JID, final UserService.ActiveStatus jidStatus) {
- User user = getUserByJID(JID);
- if (user != null) {
- int newStatus = jidStatus == UserService.ActiveStatus.Active ? 1 : 0;
- return getJdbcTemplate().update(
- "UPDATE jids SET active = ? WHERE user_id = ? AND jid = ?",
- newStatus, user.getUid(), JID) >= 0;
- }
- return false;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getAllJIDs(final User user) {
- return getJdbcTemplate().queryForList(
- "SELECT jid FROM jids WHERE user_id=?", String.class, user.getUid());
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Auth> getAuthCodes(final User user) {
- return getJdbcTemplate().query(
- "SELECT account,authcode FROM auth WHERE user_id=? AND protocol='xmpp'",
- (rs, num) -> new Auth(rs.getString(1), rs.getString(2)),
- user.getUid());
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getEmails(final User user) {
- return getJdbcTemplate().queryForList("SELECT email FROM emails WHERE user_id=?", String.class, user.getUid());
- }
-
- @Transactional(readOnly = true)
- @Override
- public String getEmailHash(final User user) {
- List<String> list = getJdbcTemplate().queryForList(
- "SELECT hash FROM mail WHERE user_id = ?",
- String.class,
- user.getUid());
- return list.isEmpty() ? StringUtils.EMPTY : list.get(0) + "@mail.juick.com";
- }
-
- @Transactional
- @Override
- public int deleteLoginForUser(final String name) {
- if (StringUtils.isBlank(name))
- return 0;
-
- return getJdbcTemplate().update(
- "delete from logins where user_id in (select id from users where nick = ?)", name);
- }
-
- @Transactional
- @Override
- public int setLoginForUser(final int uid, final String loginHash) {
- if (StringUtils.isEmpty(loginHash))
- return 0;
-
- return getNamedParameterJdbcTemplate().update(
- "INSERT INTO logins (user_id, hash) VALUES(:uid, :hash) ON DUPLICATE KEY UPDATE hash = :hash",
- new MapSqlParameterSource()
- .addValue("hash", loginHash)
- .addValue("uid", uid));
- }
-
- @Transactional
- @Override
- public void logout(int uid) {
- getJdbcTemplate().update("DELETE FROM logins WHERE user_id=?", uid);
- }
-
- @Transactional
- @Override
- public boolean deleteJID(int uid, String jid) {
- return getNamedParameterJdbcTemplate().update("DELETE FROM jids " +
- "WHERE (SELECT COUNT(*) cnt FROM (select user_id, jid FROM jids j) c WHERE user_id=:uid) > 1 " +
- "AND user_id=:uid AND jid=:jid",
- new MapSqlParameterSource()
- .addValue("uid", uid)
- .addValue("jid", jid)) > 0;
- }
-
- @Transactional
- @Override
- public boolean unauthJID(int uid, String jid) {
- return getJdbcTemplate()
- .update("DELETE FROM auth WHERE user_id=? AND protocol='xmpp' AND account=?", uid, jid) > 0;
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<String> getActiveJIDs() {
- return getJdbcTemplate().queryForList("SELECT jid FROM jids WHERE active=1 AND loginhash IS NULL", String.class);
- }
-
- @Override
- public void updateLastSeen(User user) {
- getJdbcTemplate().update("UPDATE users SET last_seen=now() WHERE id=?", user.getUid());
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/activities/ActivityListener.java b/juick-server/src/main/java/com/juick/service/activities/ActivityListener.java
deleted file mode 100644
index 863bda04..00000000
--- a/juick-server/src/main/java/com/juick/service/activities/ActivityListener.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.juick.service.activities;
-
-import org.springframework.context.event.EventListener;
-import org.springframework.scheduling.annotation.Async;
-
-public interface ActivityListener {
- @Async
- @EventListener
- void processFollowEvent(FollowEvent event);
- @Async
- @EventListener
- void undoFollowEvent(UndoFollowEvent event);
- @Async
- @EventListener
- void deleteUserEvent(DeleteUserEvent event);
- @Async
- @EventListener
- void deleteMessageEvent(DeleteMessageEvent event);
-}
diff --git a/juick-server/src/main/java/com/juick/service/activities/DeleteMessageEvent.java b/juick-server/src/main/java/com/juick/service/activities/DeleteMessageEvent.java
deleted file mode 100644
index 67e40f44..00000000
--- a/juick-server/src/main/java/com/juick/service/activities/DeleteMessageEvent.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.juick.service.activities;
-
-import com.juick.Message;
-import org.springframework.context.ApplicationEvent;
-
-public class DeleteMessageEvent extends ApplicationEvent {
- private Message message;
- /**
- * Create a new ApplicationEvent.
- *
- * @param source the object on which the event initially occurred (never {@code null})
- */
- public DeleteMessageEvent(Object source, Message message) {
- super(source);
- this.message = message;
- }
-
- public Message getMessage() {
- return message;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/activities/DeleteUserEvent.java b/juick-server/src/main/java/com/juick/service/activities/DeleteUserEvent.java
deleted file mode 100644
index 8b51da9d..00000000
--- a/juick-server/src/main/java/com/juick/service/activities/DeleteUserEvent.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.juick.service.activities;
-
-import org.springframework.context.ApplicationEvent;
-
-public class DeleteUserEvent extends ApplicationEvent {
- private String userUri;
- /**
- * Create a new ApplicationEvent.
- *
- * @param source the object on which the event initially occurred (never {@code null})
- */
- public DeleteUserEvent(Object source, String userUri) {
- super(source);
- this.userUri = userUri;
- }
-
- public String getUserUri() {
- return userUri;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/activities/FollowEvent.java b/juick-server/src/main/java/com/juick/service/activities/FollowEvent.java
deleted file mode 100644
index c96613ba..00000000
--- a/juick-server/src/main/java/com/juick/service/activities/FollowEvent.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.juick.service.activities;
-
-import com.juick.server.api.activity.model.activities.Follow;
-import org.springframework.context.ApplicationEvent;
-
-public class FollowEvent extends ApplicationEvent {
- private Follow request;
- /**
- * Create a new ApplicationEvent.
- *
- * @param source the object on which the event initially occurred (never {@code null})
- */
- public FollowEvent(Object source, Follow followRequest) {
- super(source);
- this.request = followRequest;
- }
-
- public Follow getRequest() {
- return request;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/activities/UndoFollowEvent.java b/juick-server/src/main/java/com/juick/service/activities/UndoFollowEvent.java
deleted file mode 100644
index 2b48e6f6..00000000
--- a/juick-server/src/main/java/com/juick/service/activities/UndoFollowEvent.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.juick.service.activities;
-
-import org.springframework.context.ApplicationEvent;
-
-public class UndoFollowEvent extends ApplicationEvent {
- private String actor;
- private String object;
- /**
- * Create a new ApplicationEvent.
- *
- * @param source the object on which the event initially occurred (never {@code null})
- */
- public UndoFollowEvent(Object source, String actor, String object) {
- super(source);
- this.actor = actor;
- this.object = object;
- }
-
- public String getActor() {
- return actor;
- }
-
- public String getObject() {
- return object;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java b/juick-server/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
deleted file mode 100644
index 9215d09a..00000000
--- a/juick-server/src/main/java/com/juick/service/security/HashParamAuthenticationFilter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security;
-
-import com.juick.User;
-import com.juick.service.security.entities.JuickUser;
-import com.juick.service.UserService;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
-import org.springframework.security.authentication.RememberMeAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.web.authentication.RememberMeServices;
-import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
-import org.springframework.util.Assert;
-import org.springframework.web.filter.OncePerRequestFilter;
-import org.springframework.web.util.WebUtils;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * Created by aalexeev on 4/5/17.
- */
-public class HashParamAuthenticationFilter extends OncePerRequestFilter {
- public static final String PARAM_NAME = "hash";
-
- private final UserService userService;
- private final RememberMeServices rememberMeServices;
-
-
- public HashParamAuthenticationFilter(
- final UserService userService,
- final RememberMeServices rememberMeServices) {
- Assert.notNull(userService, "userService should not be null");
- Assert.notNull(rememberMeServices, "rememberMeServices should not be null");
-
- this.userService = userService;
- this.rememberMeServices = rememberMeServices;
- }
-
- @Override
- protected void doFilterInternal(
- HttpServletRequest request,
- HttpServletResponse response,
- FilterChain filterChain) throws ServletException, IOException {
-
- String hash = getHashFromRequest(request);
-
- if (hash != null && authenticationIsRequired()) {
- User user = userService.getUserByHash(hash);
-
- if (!user.isAnonymous()) {
- User userWithPassword = userService.getUserByName(user.getName());
- userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid()));
- Authentication authentication = new RememberMeAuthenticationToken(
- ((AbstractRememberMeServices)rememberMeServices).getKey(), new JuickUser(userWithPassword), JuickUser.USER_AUTHORITY);
-
- SecurityContextHolder.getContext().setAuthentication(authentication);
-
- rememberMeServices.loginSuccess(request, response, authentication);
- }
- }
-
- filterChain.doFilter(request, response);
- }
-
- private boolean authenticationIsRequired() {
- Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
-
- return existingAuth == null ||
- !existingAuth.isAuthenticated() ||
- existingAuth instanceof AnonymousAuthenticationToken;
- }
-
- private String getHashFromRequest(HttpServletRequest request) {
- String paramHash = request.getParameter(PARAM_NAME);
- Cookie cookieHash = WebUtils.getCookie(request, PARAM_NAME);
-
- if (paramHash == null && cookieHash != null) {
- return cookieHash.getValue();
- }
- return paramHash;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/JuickUserDetailsService.java b/juick-server/src/main/java/com/juick/service/security/JuickUserDetailsService.java
deleted file mode 100644
index 59425fab..00000000
--- a/juick-server/src/main/java/com/juick/service/security/JuickUserDetailsService.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security;
-
-import com.juick.service.UserService;
-import com.juick.service.security.entities.JuickUser;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.util.Assert;
-
-/**
- * Created by aalexeev on 11/28/16.
- */
-public class JuickUserDetailsService implements UserDetailsService {
- private final UserService userService;
-
- public JuickUserDetailsService(final UserService userService) {
- Assert.notNull(userService, "UserService must be initialized");
- this.userService = userService;
- }
-
- @Override
- public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
- if (StringUtils.isBlank(username))
- throw new UsernameNotFoundException("Invalid user name " + username);
-
- com.juick.User user = userService.getUserByName(username);
-
- if (!user.isAnonymous()) {
- user.setAuthHash(userService.getHashByUID(user.getUid()));
- return new JuickUser(user);
- }
-
- throw new UsernameNotFoundException("The username " + username + " is not found");
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/NullUserDetailsService.java b/juick-server/src/main/java/com/juick/service/security/NullUserDetailsService.java
deleted file mode 100644
index 91acefa3..00000000
--- a/juick-server/src/main/java/com/juick/service/security/NullUserDetailsService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security;
-
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-
-/**
- * Created by aalexeev on 11/28/16.
- */
-public class NullUserDetailsService implements UserDetailsService {
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- throw new UsernameNotFoundException(
- "loadUserByUsername called for NullUserDetailsService, user " + username + "can not be found");
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/deprecated/CookieSimpleHashRememberMeServices.java b/juick-server/src/main/java/com/juick/service/security/deprecated/CookieSimpleHashRememberMeServices.java
deleted file mode 100644
index e385d7dd..00000000
--- a/juick-server/src/main/java/com/juick/service/security/deprecated/CookieSimpleHashRememberMeServices.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security.deprecated;
-
-import com.juick.User;
-import com.juick.service.security.entities.JuickUser;
-import com.juick.service.UserService;
-import com.juick.service.security.NullUserDetailsService;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.env.Environment;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.RememberMeServices;
-import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
-import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
-import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
-import org.springframework.util.Assert;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Optional;
-
-/**
- * Created by aalexeev on 11/28/16.
- *
- * @deprecated not recommended use for secure reasons
- */
-@Deprecated
-public class CookieSimpleHashRememberMeServices extends AbstractRememberMeServices implements RememberMeServices {
- private static final Logger logger = LoggerFactory.getLogger(CookieSimpleHashRememberMeServices.class);
-
- private static final String COOKIE_PARAM_NAME = "hash";
-
- private final UserService userService;
-
- public CookieSimpleHashRememberMeServices(
- final String key, final UserService userService, final Environment environment) {
- super(key, new NullUserDetailsService());
-
- Assert.notNull(userService);
- Assert.notNull(environment);
-
- this.userService = userService;
-
- setCookieName(COOKIE_PARAM_NAME);
- setCookieDomain(environment.getProperty("web_domain", "localhost"));
- setAlwaysRemember(true);
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
- super.logout(request, response, authentication);
- userService.deleteLoginForUser(authentication.getName());
- }
-
- @Override
- protected void onLoginSuccess(
- HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
- String username = successfulAuthentication.getName();
-
- logger.debug("Creating new persistent login for user {}", username);
-
- try {
- int uid = userService.getUIDbyName(username);
-
- Assert.isTrue(uid > 0);
-
- String hash = RandomStringUtils.randomAlphanumeric(16).toUpperCase();
-
- userService.setLoginForUser(uid, hash);
-
- setCookie(new String[]{hash}, getTokenValiditySeconds(), request, response);
- } catch (Exception e) {
- logger.error("Failed to save cookies", e);
- }
- }
-
- @Override
- protected UserDetails processAutoLoginCookie(
- String[] cookieTokens, HttpServletRequest request, HttpServletResponse response)
- throws RememberMeAuthenticationException, UsernameNotFoundException {
- String hash = cookieTokens[0];
-
- if (StringUtils.isBlank(hash)) {
- hash = request.getParameter("hash");
- }
- if (StringUtils.isBlank(hash)) {
- throw new InvalidCookieException("Cookie is invalid and hash parameter not found");
- }
-
- int uid = userService.getUIDbyHash(hash);
- if (uid <= 0)
- throw new UsernameNotFoundException("User not found by hash, cookies" + cookieTokens);
-
- Optional<User> userOptional = userService.getUserByUID(uid);
-
- Assert.isTrue(userOptional.isPresent());
-
- return new JuickUser(userService.getUserByName(userOptional.get().getName()));
- }
-
- @Override
- protected String[] decodeCookie(String cookieValue) throws InvalidCookieException {
- return new String[]{cookieValue};
- }
-
- @Override
- protected String encodeCookie(String[] cookieTokens) {
- return cookieTokens != null && cookieTokens.length > 0 ? cookieTokens[0] : StringUtils.EMPTY;
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/deprecated/RequestParamHashRememberMeServices.java b/juick-server/src/main/java/com/juick/service/security/deprecated/RequestParamHashRememberMeServices.java
deleted file mode 100644
index 3631e5a4..00000000
--- a/juick-server/src/main/java/com/juick/service/security/deprecated/RequestParamHashRememberMeServices.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security.deprecated;
-
-import com.juick.User;
-import com.juick.service.security.entities.JuickUser;
-import com.juick.service.UserService;
-import com.juick.service.security.NullUserDetailsService;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.RememberMeServices;
-import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
-import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationException;
-import org.springframework.util.Assert;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * Created by aalexeev on 11/30/16.
- *
- * @deprecated for security reasons
- */
-@Deprecated
-public class RequestParamHashRememberMeServices extends AbstractRememberMeServices implements RememberMeServices {
- private static final String PARAM_NAME = "hash";
-
- private final UserService userService;
-
- public RequestParamHashRememberMeServices(String key, UserService userService) {
- super(key, new NullUserDetailsService());
-
- Assert.notNull(userService);
- this.userService = userService;
- setAlwaysRemember(false);
- }
-
- @Override
- protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
- // do nothing
- }
-
- @Override
- protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
- return false; // always false
- }
-
- @Override
- protected void cancelCookie(HttpServletRequest request, HttpServletResponse response) {
- // do nothing
- }
-
- @Override
- protected String extractRememberMeCookie(HttpServletRequest request) {
- return PARAM_NAME; // return any not blank value
- }
-
- @Override
- protected UserDetails processAutoLoginCookie(
- String[] cookieTokens, HttpServletRequest request, HttpServletResponse response)
- throws RememberMeAuthenticationException, UsernameNotFoundException {
- String hash = request.getParameter(PARAM_NAME);
-
- if (StringUtils.isNotBlank(hash)) {
- User user = userService.getUserByHash(hash);
- if (!user.isAnonymous())
- return new JuickUser(userService.getUserByName(user.getName()));
- }
- throw new UsernameNotFoundException("User not found by hash " + hash);
- }
-}
diff --git a/juick-server/src/main/java/com/juick/service/security/entities/JuickUser.java b/juick-server/src/main/java/com/juick/service/security/entities/JuickUser.java
deleted file mode 100644
index c43f112f..00000000
--- a/juick-server/src/main/java/com/juick/service/security/entities/JuickUser.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.juick.service.security.entities;
-
-import com.juick.User;
-import com.juick.model.AnonymousUser;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by aalexeev on 11/21/16.
- */
-public class JuickUser implements UserDetails {
- static final GrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
- static final GrantedAuthority ROLE_ANONYMOUS = new SimpleGrantedAuthority("ROLE_ANONYMOUS");
-
- public static final List<GrantedAuthority> USER_AUTHORITY = Collections.singletonList(ROLE_USER);
- public static final List<GrantedAuthority> ANONYMOUS_AUTHORITY = Collections.singletonList(ROLE_ANONYMOUS);
-
- public static final JuickUser ANONYMOUS_USER = new JuickUser(AnonymousUser.INSTANCE, ANONYMOUS_AUTHORITY);
-
- private final com.juick.User user;
- private final Collection<? extends GrantedAuthority> authorities;
-
- public JuickUser(com.juick.User user) {
- this(user, USER_AUTHORITY);
- }
-
- public JuickUser(com.juick.User user, Collection<? extends GrantedAuthority> authorities) {
- this.user = user;
- this.authorities = authorities;
- }
-
- @Override
- public Collection<? extends GrantedAuthority> getAuthorities() {
- return authorities;
- }
-
- @Override
- public String getPassword() {
- return "{noop}" + user.getCredentials();
- }
-
- @Override
- public String getUsername() {
- return user.getName();
- }
-
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @Override
- public boolean isAccountNonLocked() {
- return StringUtils.isNotBlank(user.getCredentials());
- }
-
- @Override
- public boolean isCredentialsNonExpired() {
- return isAccountNonLocked();
- }
-
- @Override
- public boolean isEnabled() {
- return !user.isBanned() && isCredentialsNonExpired();
- }
-
- public User getUser() {
- return user;
- }
-}
diff --git a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java b/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java
deleted file mode 100644
index 9189c2be..00000000
--- a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.mitchellbosecke.pebble.extension;
-
-import com.mitchellbosecke.pebble.extension.filters.*;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by vitalyster on 04.05.2017.
- */
-public class FormatterExtension extends AbstractExtension {
- @Override
- public Map<String, Filter> getFilters() {
- Map<String, Filter> filters = new HashMap<>();
- filters.put("formatMessage", new FormatMessageFilter());
- filters.put("prettyTime", new PrettyTimeFilter());
- filters.put("timestamp", new TimestampFilter());
- filters.put("tagsList", new TagsListFilter());
- return filters;
- }
-}
diff --git a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java b/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java
deleted file mode 100644
index 1b75727e..00000000
--- a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatMessageFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.mitchellbosecke.pebble.extension.filters;
-
-import com.juick.Message;
-import com.juick.model.AnonymousUser;
-import com.juick.util.MessageUtils;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.extension.escaper.SafeString;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/**
- * Created by vitalyster on 04.05.2017.
- */
-public class FormatMessageFilter implements Filter {
- @Override
- public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
- if (input instanceof Message) {
- Message msg = (Message) input;
- if (msg.isHtml()) {
- return new SafeString(msg.getText());
- }
- boolean isCode = msg.getTags().stream().anyMatch(t -> t.getName().equals("code"));
- String formattedMessage = isCode ? MessageUtils.formatMessageCode(StringUtils.defaultString(msg.getText()))
- : MessageUtils.formatMessage(StringUtils.defaultString(msg.getText()));
- if (MessageUtils.isPM(msg)) {
- return new SafeString(formattedMessage);
- } else {
- String toUserString = msg.getTo().getUid() == 0 ? String.format("<a href=\"%s\" data-user-uri=\"1\">@%s</a>",
- msg.getTo().getUri().toASCIIString(), msg.getTo().getName()) : String.format("<a href=\"https://juick.com/%s/\">@%s</a>", msg.getTo().getName(), msg.getTo().getName());
- String formatString = MessageUtils.replyStartsWithQuote(msg) ? "%s,\n%s" : "%s, %s";
- String msgTxt = msg.getRid() > 0 ? String.format(formatString, toUserString, formattedMessage)
- : formattedMessage;
- return new SafeString(msgTxt);
- }
- }
- throw new IllegalArgumentException("invalid input");
- }
-
- @Override
- public List<String> getArgumentNames() {
- return null;
- }
-}
diff --git a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java b/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java
deleted file mode 100644
index 72dab20d..00000000
--- a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/PrettyTimeFilter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.mitchellbosecke.pebble.extension.filters;
-
-import com.juick.util.PrettyTimeFormatter;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
-
-import java.time.Instant;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Created by vitalyster on 04.05.2017.
- */
-public class PrettyTimeFilter implements Filter {
-
- PrettyTimeFormatter formatter = new PrettyTimeFormatter();
-
- @Override
- public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
- if (input instanceof Instant) {
- Locale locale = context.getLocale();
- return formatter.format(locale, Date.from((Instant)input));
- }
- throw new IllegalArgumentException("invalid input");
- }
-
- @Override
- public List<String> getArgumentNames() {
- return null;
- }
-}
diff --git a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java b/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
deleted file mode 100644
index c7b00ea3..00000000
--- a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TagsListFilter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.mitchellbosecke.pebble.extension.filters;
-
-import com.juick.Tag;
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * Created by vitalyster on 23.05.2017.
- */
-public class TagsListFilter implements Filter {
- @SuppressWarnings("unchecked")
- @Override
- public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
- return ((List<Tag>) input).stream().map(Tag::getName).collect(Collectors.toList());
- }
-
- @Override
- public List<String> getArgumentNames() {
- return null;
- }
-}
diff --git a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java b/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java
deleted file mode 100644
index 5f98c167..00000000
--- a/juick-server/src/main/java/com/mitchellbosecke/pebble/extension/filters/TimestampFilter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.mitchellbosecke.pebble.extension.filters;
-
-import com.mitchellbosecke.pebble.extension.Filter;
-import com.mitchellbosecke.pebble.template.EvaluationContext;
-import com.mitchellbosecke.pebble.template.PebbleTemplate;
-
-import java.time.Instant;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-public class TimestampFilter implements Filter {
- @Override
- public Object apply(Object input, Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
- if (input instanceof Instant) {
- return Date.from((Instant)input);
- }
- throw new IllegalArgumentException("invalid input");
- }
-
- @Override
- public List<String> getArgumentNames() {
- return null;
- }
-}
diff --git a/juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java b/juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java
deleted file mode 100644
index aae49bc7..00000000
--- a/juick-server/src/main/java/rocks/xmpp/core/session/debug/LogbackDebugger.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008-2017, Juick
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package rocks.xmpp.core.session.debug;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import rocks.xmpp.core.session.XmppSession;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Created by vitalyster on 17.11.2016.
- */
-public class LogbackDebugger implements XmppDebugger {
- private Logger logger;
-
- @Override
- public void initialize(XmppSession xmppSession) {
- logger = LoggerFactory.getLogger("com.juick.server.xmpp");
- }
-
- @Override
- public void writeStanza(String s, Object o) {
- logger.info("OUT: {}", s);
- }
-
- @Override
- public void readStanza(String s, Object o) {
- logger.info("IN: {}", s);
- }
-
- @Override
- public OutputStream createOutputStream(OutputStream outputStream) {
- return outputStream;
- }
-
- @Override
- public InputStream createInputStream(InputStream inputStream) {
- return inputStream;
- }
-}
diff --git a/juick-server/src/main/java/ru/sape/Sape.java b/juick-server/src/main/java/ru/sape/Sape.java
deleted file mode 100644
index 38577c45..00000000
--- a/juick-server/src/main/java/ru/sape/Sape.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * http://code.google.com/p/javasape/
- */
-package ru.sape;
-
-public class Sape {
-
- private final String sapeUser;
- private final SapeConnection sapePageLinkConnection;
-
- public Sape(String sapeUser, String host, int socketTimeout, int cacheLifeTime) {
- this.sapeUser = sapeUser;
-
- this.sapePageLinkConnection = new SapeConnection(
- "/code.php?user=" + sapeUser + "&host=" + host,
- "SAPE_Client PHP", socketTimeout, cacheLifeTime);
- }
- public boolean debug = false;
-
- public SapePageLinks getPageLinks(String requestUri, String cookie) {
- return new SapePageLinks(sapePageLinkConnection, sapeUser, requestUri, cookie, debug);
- }
-}
diff --git a/juick-server/src/main/java/ru/sape/SapeConnection.java b/juick-server/src/main/java/ru/sape/SapeConnection.java
deleted file mode 100644
index a15658fa..00000000
--- a/juick-server/src/main/java/ru/sape/SapeConnection.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package ru.sape;
-
-import com.github.ooxi.phparser.SerializedPhpParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.*;
-
-public class SapeConnection {
- private static final Logger logger = LoggerFactory.getLogger(SapeConnection.class);
- private final String version = "1.0.3";
- private final List<String> serverList = Arrays.asList("dispenser-01.sape.ru", "dispenser-02.sape.ru");
- private final String dispenserPath;
- private final String userAgent;
- private final int socketTimeout;
- private final int cacheLifeTime;
-
- public SapeConnection(String dispenserPath, String userAgent, int socketTimeout, int cacheLifeTime) {
- this.dispenserPath = dispenserPath;
- this.userAgent = userAgent;
- this.socketTimeout = socketTimeout;
- this.cacheLifeTime = cacheLifeTime;
- }
-
- protected String fetchRemoteFile(String host, String path) throws IOException {
- Reader r = null;
-
- try {
- HttpURLConnection connection = (HttpURLConnection) ((new URL(("http://" + host + path)).openConnection()));
-
- if (socketTimeout > 0) {
- connection.setConnectTimeout(socketTimeout);
- connection.setReadTimeout(socketTimeout);
- }
-
- connection.addRequestProperty("User-Agent", userAgent + ' ' + version);
-
- connection.setDoOutput(true);
- connection.setDoInput(true);
- connection.setUseCaches(false);
- connection.setRequestMethod("GET");
- connection.connect();
-
- r = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
-
- StringWriter sw = new StringWriter();
-
- int b;
-
- while ((b = r.read()) != -1) {
- sw.write(b);
- }
-
- return sw.toString();
- } finally {
- if (r != null) {
- r.close();
- }
- }
- }
- Map<String, Object> cached;
- long cacheUpdated;
-
- @SuppressWarnings("unchecked")
- public Map<String, Object> getData() {
- if (cacheLifeTime <= (System.currentTimeMillis() - cacheUpdated) / 1000) {
- for (String server : serverList) {
- String data;
-
- try {
- data = fetchRemoteFile(server, dispenserPath + "&charset=UTF-8");
- } catch (IOException e1) {
- continue;
- }
-
- if (data.startsWith("FATAL ERROR:")) {
- logger.error("Sape responded with error: {}", data);
-
- continue;
- }
-
- try {
- cached = (Map<String, Object>) new SerializedPhpParser(data).parse();
- } catch (Exception e) {
- logger.error("Can't parse Sape data", e);
- continue;
- }
-
- cacheUpdated = System.currentTimeMillis();
-
- return cached;
- }
-
- logger.error("Unable to fetch Sape data");
-
- return Collections.emptyMap();
- }
-
- return cached;
- }
-}
diff --git a/juick-server/src/main/java/ru/sape/SapePageLinks.java b/juick-server/src/main/java/ru/sape/SapePageLinks.java
deleted file mode 100644
index e89b4e71..00000000
--- a/juick-server/src/main/java/ru/sape/SapePageLinks.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package ru.sape;
-
-import java.util.*;
-
-public class SapePageLinks {
-
- private boolean showCode;
-
- public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, String sapeCookie) {
- this(sapeConnection, sapeUser, requestUri, sapeCookie, false);
- }
-
- @SuppressWarnings("unchecked")
- public SapePageLinks(SapeConnection sapeConnection, String sapeUser, String requestUri, String sapeCookie, boolean showCode) {
- if (sapeUser.equals(sapeCookie)) {
- showCode = true;
- }
-
- Map<String, Object> data = sapeConnection.getData();
-
- if (data.containsKey("__sape_delimiter__")) {
- linkDelimiter = (String) data.get("__sape_delimiter__");
- }
-
- if (data.containsKey(requestUri)) {
- pageLinks = new ArrayList<>(((Map<Object, String>) data.get(requestUri)).values());
- }
-
- if (data.containsKey("__sape_new_url__")) {
- if (showCode) {
- Object newUrl = data.get("__sape_new_url__");
-
- if (newUrl instanceof Map) {
- pageLinks = new ArrayList<>(((Map<Object, String>) newUrl).values());
- } else {
- pageLinks = new ArrayList<>(Collections.singletonList((String) newUrl));
- }
- }
- }
-
- this.showCode = showCode;
- }
- private String linkDelimiter = ".";
- private List<String> pageLinks = new ArrayList<>();
-
- public String render() {
- return render(-1);
- }
-
- public String render(int count) {
- StringBuilder s = new StringBuilder();
-
- if (count < 0) {
- count = pageLinks.size();
- }
-
- for (Iterator<String> i = pageLinks.iterator(); i.hasNext() && count > 0; count--) {
- if (s.length() > 0) {
- s.append(linkDelimiter);
- }
-
- String l = i.next();
-
- s.append(l);
-
- i.remove();
- }
-
- if (showCode) {
- s.insert(0, "<sape_noindex>");
- s.append("</sape_noindex>");
- }
-
- return s.toString();
- }
-}
diff --git a/juick-server/src/main/resources/1x1.png b/juick-server/src/main/resources/1x1.png
deleted file mode 100644
index 1914264c..00000000
--- a/juick-server/src/main/resources/1x1.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/Transparent.gif b/juick-server/src/main/resources/Transparent.gif
deleted file mode 100644
index f191b280..00000000
--- a/juick-server/src/main/resources/Transparent.gif
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/db/migration/V1.10__favorites_user_uri.sql b/juick-server/src/main/resources/db/migration/V1.10__favorites_user_uri.sql
deleted file mode 100644
index 8f382398..00000000
--- a/juick-server/src/main/resources/db/migration/V1.10__favorites_user_uri.sql
+++ /dev/null
@@ -1,3 +0,0 @@
-ALTER TABLE favorites ADD COLUMN user_uri char(255) DEFAULT NULL;
-UPDATE favorites SET user_uri='' WHERE user_uri IS NULL;
-ALTER TABLE favorites MODIFY COLUMN user_uri char(255) NOT NULL DEFAULT ''; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.11__increase pm timestamp precision.sql b/juick-server/src/main/resources/db/migration/V1.11__increase pm timestamp precision.sql
deleted file mode 100644
index e83eb621..00000000
--- a/juick-server/src/main/resources/db/migration/V1.11__increase pm timestamp precision.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE pm MODIFY COLUMN ts timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.12__drop unused tables.sql b/juick-server/src/main/resources/db/migration/V1.12__drop unused tables.sql
deleted file mode 100644
index 1599f5f6..00000000
--- a/juick-server/src/main/resources/db/migration/V1.12__drop unused tables.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-DROP TABLE IF EXISTS messages_votes;
-DROP TABLE IF EXISTS reader_links;
-DROP TABLE IF EXISTS reader_rss;
-DROP TABLE IF EXISTS captcha;
-DROP TABLE IF EXISTS captchaimg; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.13__drop unused tables.sql b/juick-server/src/main/resources/db/migration/V1.13__drop unused tables.sql
deleted file mode 100644
index c35fc92c..00000000
--- a/juick-server/src/main/resources/db/migration/V1.13__drop unused tables.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-DROP TABLE IF EXISTS ads_messages;
-DROP TABLE IF EXISTS ads_messages_log;
-DROP TABLE IF EXISTS presence;
-DROP TABLE IF EXISTS friends_facebook;
-DROP TABLE IF EXISTS users_refs; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.14__drop broken pm_streams.sql b/juick-server/src/main/resources/db/migration/V1.14__drop broken pm_streams.sql
deleted file mode 100644
index 448c5ce2..00000000
--- a/juick-server/src/main/resources/db/migration/V1.14__drop broken pm_streams.sql
+++ /dev/null
@@ -1 +0,0 @@
-DROP TABLE IF EXISTS pm_streams; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.15__drop unused columns add ts for some tables.sql b/juick-server/src/main/resources/db/migration/V1.15__drop unused columns add ts for some tables.sql
deleted file mode 100644
index 6b3ab388..00000000
--- a/juick-server/src/main/resources/db/migration/V1.15__drop unused columns add ts for some tables.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE subscr_users DROP COLUMN `jid`;
-ALTER TABLE subscr_users DROP COLUMN `active`;
-ALTER TABLE auth ADD COLUMN ts timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP;
-ALTER TABLE mail ADD COLUMN ts timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.16__last seen.sql b/juick-server/src/main/resources/db/migration/V1.16__last seen.sql
deleted file mode 100644
index 52ca4e90..00000000
--- a/juick-server/src/main/resources/db/migration/V1.16__last seen.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE users ADD COLUMN last_seen timestamp(6) NULL;
-UPDATE users SET last_seen=lastmessage; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.1__Add updated_at field.sql b/juick-server/src/main/resources/db/migration/V1.1__Add updated_at field.sql
deleted file mode 100644
index dac179b1..00000000
--- a/juick-server/src/main/resources/db/migration/V1.1__Add updated_at field.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-ALTER TABLE messages_txt ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
-ALTER TABLE replies ADD COLUMN updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
diff --git a/juick-server/src/main/resources/db/migration/V1.2__Drop telegram_chats.sql b/juick-server/src/main/resources/db/migration/V1.2__Drop telegram_chats.sql
deleted file mode 100644
index c8faee0d..00000000
--- a/juick-server/src/main/resources/db/migration/V1.2__Drop telegram_chats.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-INSERT INTO telegram(tg_id, tg_name, loginhash) SELECT chat_id AS tg_id, 'Anonymous', UUID() FROM telegram_chats;
-DROP TABLE telegram_chats; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql b/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql
deleted file mode 100644
index ced85ade..00000000
--- a/juick-server/src/main/resources/db/migration/V1.3__Nullable user_id column in auth table.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE auth MODIFY COLUMN user_id int(10) unsigned NULL; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.4__ActivityPub followers.sql b/juick-server/src/main/resources/db/migration/V1.4__ActivityPub followers.sql
deleted file mode 100644
index 16b39f62..00000000
--- a/juick-server/src/main/resources/db/migration/V1.4__ActivityPub followers.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-CREATE TABLE IF NOT EXISTS `followers` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `acct` char(64) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `acct` (`acct`),
- foreign key (user_id) references users(id)
-); \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.5__Drop acct index.sql b/juick-server/src/main/resources/db/migration/V1.5__Drop acct index.sql
deleted file mode 100644
index 58757d88..00000000
--- a/juick-server/src/main/resources/db/migration/V1.5__Drop acct index.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-ALTER TABLE followers ADD COLUMN `acct_migr` char(64) NOT NULL;
-UPDATE followers SET `acct_migr` = `acct`;
-ALTER TABLE followers DROP COLUMN `acct`;
-ALTER TABLE followers ADD COLUMN `acct` char(64) NOT NULL;
-UPDATE followers SET `acct` = `acct_migr`;
-ALTER TABLE followers DROP COLUMN `acct_migr`; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.6__user_uri.sql b/juick-server/src/main/resources/db/migration/V1.6__user_uri.sql
deleted file mode 100644
index c302907c..00000000
--- a/juick-server/src/main/resources/db/migration/V1.6__user_uri.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE replies ADD COLUMN user_uri char(255) DEFAULT NULL; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.7__reply_uri.sql b/juick-server/src/main/resources/db/migration/V1.7__reply_uri.sql
deleted file mode 100644
index 9ec35485..00000000
--- a/juick-server/src/main/resources/db/migration/V1.7__reply_uri.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE replies ADD COLUMN reply_uri char(255) DEFAULT NULL; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.8__html reply.sql b/juick-server/src/main/resources/db/migration/V1.8__html reply.sql
deleted file mode 100644
index 9f939971..00000000
--- a/juick-server/src/main/resources/db/migration/V1.8__html reply.sql
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE replies ADD COLUMN html tinyint(4) NOT NULL DEFAULT '0'; \ No newline at end of file
diff --git a/juick-server/src/main/resources/db/migration/V1.9__reply_uri_index.sql b/juick-server/src/main/resources/db/migration/V1.9__reply_uri_index.sql
deleted file mode 100644
index 0ee3c77f..00000000
--- a/juick-server/src/main/resources/db/migration/V1.9__reply_uri_index.sql
+++ /dev/null
@@ -1 +0,0 @@
-create index reply_uri_index on replies(reply_uri) \ No newline at end of file
diff --git a/juick-server/src/main/resources/errors.properties b/juick-server/src/main/resources/errors.properties
deleted file mode 100644
index 7ec8fbfd..00000000
--- a/juick-server/src/main/resources/errors.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-error.title = Error page
-
-error.login=Wrong user or password \ No newline at end of file
diff --git a/juick-server/src/main/resources/errors_ru.properties b/juick-server/src/main/resources/errors_ru.properties
deleted file mode 100644
index ca13b926..00000000
--- a/juick-server/src/main/resources/errors_ru.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-error.title = Произошла ошибка
-
-error.login=Произошла ошибка, проверьте имя пользователя и пароль \ No newline at end of file
diff --git a/juick-server/src/main/resources/help b/juick-server/src/main/resources/help
deleted file mode 160000
-Subproject ce103cd9a2a8a200c6ebb3b41525e7c8f639d98
diff --git a/juick-server/src/main/resources/juick.png b/juick-server/src/main/resources/juick.png
deleted file mode 100644
index a7b0e901..00000000
--- a/juick-server/src/main/resources/juick.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/juick.sql b/juick-server/src/main/resources/juick.sql
deleted file mode 100644
index a6fb76cd..00000000
--- a/juick-server/src/main/resources/juick.sql
+++ /dev/null
@@ -1,947 +0,0 @@
--- MySQL dump 10.16 Distrib 10.1.26-MariaDB, for debian-linux-gnu (x86_64)
---
--- Host: localhost Database: juick
--- ------------------------------------------------------
-use juick;
--- Server version 10.1.26-MariaDB-0+deb9u1
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8mb4 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Table structure for table `ads_messages`
---
-
-DROP TABLE IF EXISTS `ads_messages`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `ads_messages` (
- `message_id` int(10) unsigned NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `ads_messages_log`
---
-
-DROP TABLE IF EXISTS `ads_messages_log`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `ads_messages_log` (
- `user_id` int(10) unsigned NOT NULL,
- `message_id` int(10) unsigned NOT NULL,
- `ts` int(10) unsigned NOT NULL DEFAULT '0'
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `android`
---
-
-DROP TABLE IF EXISTS `android`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `android` (
- `user_id` int(10) unsigned NOT NULL,
- `regid` char(255) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `regid` (`regid`),
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `auth`
---
-
-DROP TABLE IF EXISTS `auth`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `auth` (
- `user_id` int(10) unsigned NOT NULL,
- `protocol` enum('xmpp','email','sms') NOT NULL,
- `account` char(64) NOT NULL,
- `authcode` char(8) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `bl_tags`
---
-
-DROP TABLE IF EXISTS `bl_tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `bl_tags` (
- `user_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL,
- KEY `tag_id` (`tag_id`),
- KEY `user_id` (`user_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `bl_users`
---
-
-DROP TABLE IF EXISTS `bl_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `bl_users` (
- `user_id` int(10) unsigned NOT NULL,
- `bl_user_id` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- PRIMARY KEY (`user_id`,`bl_user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `captcha`
---
-
-DROP TABLE IF EXISTS `captcha`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `captcha` (
- `jid` char(64) NOT NULL,
- `hash` char(16) NOT NULL,
- `confirmed` tinyint(4) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `captchaimg`
---
-
-DROP TABLE IF EXISTS `captchaimg`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `captchaimg` (
- `id` char(16) NOT NULL,
- `txt` char(6) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `ip` char(16) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `emails`
---
-
-DROP TABLE IF EXISTS `emails`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `emails` (
- `user_id` int(10) unsigned NOT NULL,
- `email` char(64) NOT NULL,
- `subscr_hour` tinyint(4) DEFAULT NULL,
- KEY `email` (`email`) USING HASH
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `facebook`
---
-
-DROP TABLE IF EXISTS `facebook`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `facebook` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `fb_id` bigint(20) unsigned DEFAULT NULL,
- `loginhash` char(36) DEFAULT NULL,
- `access_token` char(255) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `fb_name` char(64) DEFAULT NULL,
- `fb_link` char(255) DEFAULT NULL,
- `crosspost` tinyint(1) unsigned NOT NULL DEFAULT '1',
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `favorites`
---
-
-DROP TABLE IF EXISTS `favorites`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `favorites` (
- `user_id` int(10) unsigned NOT NULL,
- `message_id` int(10) unsigned NOT NULL,
- `ts` datetime NOT NULL,
- `like_id` int(10) unsigned NOT NULL DEFAULT '1',
- KEY `user_id` (`user_id`),
- KEY `message_id` (`message_id`),
- KEY `like_id` (`like_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `friends_facebook`
---
-
-DROP TABLE IF EXISTS `friends_facebook`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `friends_facebook` (
- `user_id` int(10) unsigned NOT NULL,
- `friend_id` bigint(20) unsigned NOT NULL,
- UNIQUE KEY `user_id` (`user_id`,`friend_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `images`
---
-
-DROP TABLE IF EXISTS `images`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `images` (
- `mid` int(10) unsigned NOT NULL,
- `rid` int(10) unsigned NOT NULL,
- `thumb` int(10) unsigned NOT NULL,
- `small` int(10) unsigned NOT NULL,
- `medium` int(10) unsigned NOT NULL,
- `height` int(10) unsigned NOT NULL,
- `width` int(10) unsigned NOT NULL,
- PRIMARY KEY (`mid`,`rid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `ios`
---
-
-DROP TABLE IF EXISTS `ios`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `ios` (
- `user_id` int(10) unsigned NOT NULL,
- `token` char(64) COLLATE utf8mb4_unicode_ci NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `token` (`token`),
- KEY `user_id` (`user_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `jids`
---
-
-DROP TABLE IF EXISTS `jids`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `jids` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `jid` char(64) NOT NULL,
- `active` tinyint(1) NOT NULL DEFAULT '1',
- `loginhash` char(36) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `jid` (`jid`),
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `logins`
---
-
-DROP TABLE IF EXISTS `logins`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `logins` (
- `user_id` int(10) unsigned NOT NULL,
- `hash` char(16) NOT NULL,
- UNIQUE KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `mail`
---
-
-DROP TABLE IF EXISTS `mail`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `mail` (
- `user_id` int(10) unsigned NOT NULL,
- `hash` char(16) NOT NULL,
- PRIMARY KEY (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `meon`
---
-
-DROP TABLE IF EXISTS `meon`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `meon` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `user_id` int(10) unsigned NOT NULL,
- `link` char(255) NOT NULL,
- `name` char(32) NOT NULL,
- `ico` smallint(5) unsigned DEFAULT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messages`
---
-
-DROP TABLE IF EXISTS `messages`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messages` (
- `message_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `user_id` int(10) unsigned NOT NULL,
- `lang` enum('en','ru','fr','fa','__') NOT NULL DEFAULT '__',
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `replies` smallint(5) unsigned NOT NULL DEFAULT '0',
- `maxreplyid` smallint(5) unsigned NOT NULL DEFAULT '0',
- `privacy` tinyint(4) NOT NULL DEFAULT '1',
- `readonly` tinyint(1) NOT NULL DEFAULT '0',
- `attach` enum('jpg','mp4','png') DEFAULT NULL,
- `place_id` int(10) unsigned DEFAULT NULL,
- `lat` decimal(10,7) DEFAULT NULL,
- `lon` decimal(10,7) DEFAULT NULL,
- `popular` tinyint(4) NOT NULL DEFAULT '0',
- `hidden` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `likes` smallint(6) NOT NULL DEFAULT '0',
- `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`message_id`),
- KEY `user_id` (`user_id`),
- KEY `ts` (`ts`),
- KEY `attach` (`attach`),
- KEY `place_id` (`place_id`),
- KEY `popular` (`popular`),
- KEY `hidden` (`hidden`),
- KEY `updated_indx` (`updated`,`message_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messages_access`
---
-
-DROP TABLE IF EXISTS `messages_access`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messages_access` (
- `message_id` int(10) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL,
- KEY `message_id` (`message_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messages_tags`
---
-
-DROP TABLE IF EXISTS `messages_tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messages_tags` (
- `message_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL,
- UNIQUE KEY `message_id_2` (`message_id`,`tag_id`),
- KEY `message_id` (`message_id`),
- KEY `tag_id` (`tag_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messages_txt`
---
-
-DROP TABLE IF EXISTS `messages_txt`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messages_txt` (
- `message_id` int(10) unsigned NOT NULL,
- `tags` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
- `repliesby` varchar(96) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
- `txt` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- PRIMARY KEY (`message_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messages_votes`
---
-
-DROP TABLE IF EXISTS `messages_votes`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messages_votes` (
- `message_id` int(10) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `vote` tinyint(4) NOT NULL DEFAULT '1',
- UNIQUE KEY `message_id` (`message_id`,`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `messenger`
---
-
-DROP TABLE IF EXISTS `messenger`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `messenger` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `sender_id` bigint(20) NOT NULL,
- `display_name` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `loginhash` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `places`
---
-
-DROP TABLE IF EXISTS `places`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `places` (
- `place_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `lat` decimal(10,7) NOT NULL,
- `lon` decimal(10,7) NOT NULL,
- `name` char(64) NOT NULL,
- `descr` char(255) DEFAULT NULL,
- `url` char(128) DEFAULT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- PRIMARY KEY (`place_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `places_tags`
---
-
-DROP TABLE IF EXISTS `places_tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `places_tags` (
- `place_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `pm`
---
-
-DROP TABLE IF EXISTS `pm`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `pm` (
- `user_id` int(10) unsigned NOT NULL,
- `user_id_to` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- `txt` text NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `pm_inroster`
---
-
-DROP TABLE IF EXISTS `pm_inroster`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `pm_inroster` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(64) NOT NULL,
- UNIQUE KEY `user_id_2` (`user_id`,`jid`),
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `pm_streams`
---
-
-DROP TABLE IF EXISTS `pm_streams`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `pm_streams` (
- `user_id` int(10) unsigned NOT NULL,
- `user_id_to` int(10) unsigned NOT NULL,
- `lastmessage` datetime NOT NULL,
- `lastview` datetime DEFAULT NULL,
- `unread` smallint(5) unsigned NOT NULL DEFAULT '0',
- UNIQUE KEY `user_id` (`user_id`,`user_id_to`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `presence`
---
-
-DROP TABLE IF EXISTS `presence`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `presence` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(64) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- UNIQUE KEY `jid` (`jid`)
-) ENGINE=MEMORY DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `reactions`
---
-
-DROP TABLE IF EXISTS `reactions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `reactions` (
- `like_id` int(10) unsigned NOT NULL,
- `description` varchar(100) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `reader_links`
---
-
-DROP TABLE IF EXISTS `reader_links`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `reader_links` (
- `link_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `rss_id` int(10) unsigned NOT NULL,
- `url` char(255) NOT NULL,
- `title` char(255) NOT NULL,
- `ts` datetime NOT NULL,
- PRIMARY KEY (`link_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `reader_rss`
---
-
-DROP TABLE IF EXISTS `reader_rss`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `reader_rss` (
- `rss_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `url` char(255) NOT NULL,
- `lastcheck` datetime NOT NULL,
- PRIMARY KEY (`rss_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `replies`
---
-
-DROP TABLE IF EXISTS `replies`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `replies` (
- `message_id` int(10) unsigned NOT NULL,
- `reply_id` smallint(5) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `replyto` smallint(5) unsigned NOT NULL DEFAULT '0',
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `attach` enum('jpg','mp4','png') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
- `txt` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
- KEY `ts` (`ts`),
- KEY `message_id` (`message_id`),
- KEY `uid` (`user_id`),
- KEY `reply_indx` (`message_id`,`reply_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `search`
---
-
-DROP TABLE IF EXISTS `search`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `search` (
- `id` bigint(20) unsigned NOT NULL,
- `weight` int(11) NOT NULL,
- `query` varchar(3072) NOT NULL,
- `group_id` int(11) DEFAULT NULL,
- KEY `query` (`query`(768))
-) ENGINE=SPHINX DEFAULT CHARSET=utf8mb4 CONNECTION='sphinx://127.0.0.1:3312/messages';
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `sphinx`
---
-
-DROP TABLE IF EXISTS `sphinx`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `sphinx` (
- `counter_id` tinyint(3) unsigned NOT NULL,
- `max_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`counter_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `subscr_messages`
---
-
-DROP TABLE IF EXISTS `subscr_messages`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `subscr_messages` (
- `message_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- `last_read_rid` smallint(5) NOT NULL DEFAULT '0',
- UNIQUE KEY `message_id` (`message_id`,`suser_id`),
- KEY `last_read_indx` (`suser_id`,`last_read_rid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `subscr_tags`
---
-
-DROP TABLE IF EXISTS `subscr_tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `subscr_tags` (
- `tag_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- UNIQUE KEY `tag_id` (`tag_id`,`suser_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `subscr_users`
---
-
-DROP TABLE IF EXISTS `subscr_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `subscr_users` (
- `user_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- `jid` char(64) DEFAULT NULL,
- `active` bit(1) NOT NULL DEFAULT b'1',
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `user_id` (`user_id`,`suser_id`),
- KEY `suser_id` (`suser_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `tags`
---
-
-DROP TABLE IF EXISTS `tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `tags` (
- `tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `synonym_id` int(10) unsigned DEFAULT NULL,
- `name` char(70) CHARACTER SET utf8mb4 DEFAULT NULL,
- `top` tinyint(1) unsigned NOT NULL DEFAULT '0',
- `noindex` tinyint(1) unsigned NOT NULL DEFAULT '0',
- `stat_messages` int(10) unsigned NOT NULL DEFAULT '0',
- `stat_users` smallint(5) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`tag_id`),
- KEY `synonym_id` (`synonym_id`),
- KEY `stat_msg_indx` (`name`,`stat_messages`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `tags_ignore`
---
-
-DROP TABLE IF EXISTS `tags_ignore`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `tags_ignore` (
- `tag_id` int(10) unsigned NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `tags_synonyms`
---
-
-DROP TABLE IF EXISTS `tags_synonyms`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `tags_synonyms` (
- `name` char(64) NOT NULL,
- `changeto` char(64) NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `telegram`
---
-
-DROP TABLE IF EXISTS `telegram`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `telegram` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `tg_id` bigint(20) NOT NULL,
- `tg_name` char(64) COLLATE utf8mb4_unicode_ci NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `loginhash` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `telegram_chats`
---
-
-DROP TABLE IF EXISTS `telegram_chats`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `telegram_chats` (
- `chat_id` bigint(20) DEFAULT NULL,
- UNIQUE KEY `chat_id` (`chat_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `top_ignore_messages`
---
-
-DROP TABLE IF EXISTS `top_ignore_messages`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `top_ignore_messages` (
- `message_id` int(10) unsigned NOT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `top_ignore_tags`
---
-
-DROP TABLE IF EXISTS `top_ignore_tags`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `top_ignore_tags` (
- `tag_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`tag_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `top_ignore_users`
---
-
-DROP TABLE IF EXISTS `top_ignore_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `top_ignore_users` (
- `user_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `twitter`
---
-
-DROP TABLE IF EXISTS `twitter`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `twitter` (
- `user_id` int(10) unsigned NOT NULL,
- `access_token` char(64) NOT NULL,
- `access_token_secret` char(64) NOT NULL,
- `uname` char(64) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `crosspost` tinyint(1) unsigned NOT NULL DEFAULT '1',
- PRIMARY KEY (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `useroptions`
---
-
-DROP TABLE IF EXISTS `useroptions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `useroptions` (
- `user_id` int(10) unsigned NOT NULL,
- `jnotify` tinyint(1) NOT NULL DEFAULT '1',
- `subscr_active` tinyint(1) NOT NULL DEFAULT '1',
- `off_ts` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- `xmppxhtml` tinyint(1) NOT NULL DEFAULT '0',
- `subscr_notify` tinyint(1) NOT NULL DEFAULT '1',
- `recommendations` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_view` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_reply` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_pm` tinyint(1) NOT NULL DEFAULT '1',
- `repliesview` tinyint(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`user_id`),
- KEY `recommendations` (`recommendations`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `users`
---
-
-DROP TABLE IF EXISTS `users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `users` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `nick` char(64) NOT NULL,
- `passw` char(32) NOT NULL,
- `lang` enum('en','ru','fr','fa','__') NOT NULL DEFAULT '__',
- `banned` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `lastmessage` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `lastpm` int(11) NOT NULL DEFAULT '0',
- `lastphoto` int(11) NOT NULL DEFAULT '0',
- `karma` smallint(6) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`),
- UNIQUE KEY `nick` (`nick`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `users_refs`
---
-
-DROP TABLE IF EXISTS `users_refs`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `users_refs` (
- `user_id` int(10) unsigned NOT NULL,
- `ref` int(10) unsigned NOT NULL,
- KEY `ref` (`ref`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `users_subscr`
---
-
-DROP TABLE IF EXISTS `users_subscr`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `users_subscr` (
- `user_id` int(10) unsigned NOT NULL,
- `cnt` smallint(5) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `usersinfo`
---
-
-DROP TABLE IF EXISTS `usersinfo`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `usersinfo` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(32) DEFAULT NULL,
- `fullname` char(32) DEFAULT NULL,
- `country` char(32) DEFAULT NULL,
- `url` char(64) DEFAULT NULL,
- `gender` char(32) DEFAULT NULL,
- `bday` char(10) DEFAULT NULL,
- `descr` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `version`
---
-
-DROP TABLE IF EXISTS `version`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `version` (
- `version` bigint(20) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `vk`
---
-
-DROP TABLE IF EXISTS `vk`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `vk` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `vk_id` bigint(20) unsigned DEFAULT NULL,
- `loginhash` char(36) DEFAULT NULL,
- `access_token` char(128) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `vk_name` char(64) DEFAULT NULL,
- `vk_link` char(64) NOT NULL,
- `crosspost` tinyint(3) unsigned NOT NULL DEFAULT '1',
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `winphone`
---
-
-DROP TABLE IF EXISTS `winphone`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `winphone` (
- `user_id` int(10) unsigned NOT NULL,
- `url` char(255) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `url` (`url`),
- KEY `user_id` (`user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `wl_users`
---
-
-DROP TABLE IF EXISTS `wl_users`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `wl_users` (
- `user_id` int(10) unsigned NOT NULL,
- `wl_user_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`user_id`,`wl_user_id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Dump completed on 2018-06-22 7:38:17
diff --git a/juick-server/src/main/resources/messages.properties b/juick-server/src/main/resources/messages.properties
deleted file mode 100644
index cfd8a826..00000000
--- a/juick-server/src/main/resources/messages.properties
+++ /dev/null
@@ -1,80 +0,0 @@
-date.format=MM/dd/yyyy
-
-link.settings=Settings
-link.returnToMain=Back to Home Page
-link.contacts=Contacts
-link.tos=TOS
-link.adv=Advertisement
-
-link.popular=Popular
-link.allMessages=Discover
-link.withPhotos=Photos
-link.trends=Trends
-link.my=My feed
-link.privateMessages=PM
-link.discuss=Discuss
-link.recommended=Recommended
-link.postMessage=Post
-link.Login=Login
-link.logout=Logout
-
-link.settings.main=Main
-link.settings.password=Password
-link.settings.about=About
-
-label.sponsor=Sponsor
-label.sponsors=Sponsors
-label.search=Search
-label.register=Register
-label.username=User name
-label.password=Password
-
-postForm.newMessage=New message...
-postForm.imageLink=Link to image
-postForm.imageFormats=JPG/PNG, up to 10 MB
-postForm.or=or
-postForm.upload=Upload
-postForm.tags=Tags (space separated)
-postForm.submit=Send
-
-message.recommend=Recommend
-message.recommendedBy=♡ recommended by
-message.recommendedOthers=and {0} others
-message.comment=Comment
-message.writeComment=Write a comment...
-message.share=Share
-message.subscribe=Subscribe
-message.subscribed=Subscribed
-message.delete=Delete
-message.loginForSending=<a href="{0}" class="a-login">Login</a> to post messages and comments
-message.sendLoginToXmpp=Send <b>LOGIN</b> to <a href="xmpp:juick@juick.com?message;body=LOGIN">juick@juick.com</a>
-
-messages.next=Next
-
-reply.reply=Reply
-reply.inReplyTo=in reply to
-reply.replies=Replies
-
-replies.showAsList=Show as list
-replies.showAsTree=Show as tree
-replies.unfoldAll=Unfold all
-
-question.areRegistered=Already registered?
-
-title.help=Help
-title.loginOrSignup=Juick - Log In or Sign Up
-title.index.anonym=Juick microblogs: popular posts
-title.index.user=Popular
-
-error.pageNotFound=Page not found
-error.pageNotFound.description=User probably deleted this post, or this page never existed.
-
-blog.blog=Blog
-blog.recommendations=Recommendations
-blog.photos=Photos
-blog.iread=I read
-blog.readers=My readers
-blog.bl=My blacklist
-blog.messages=Messages
-blog.comments=Comments
-blog.allPostsWithTag=All posts tagged \ No newline at end of file
diff --git a/juick-server/src/main/resources/messages_ru.properties b/juick-server/src/main/resources/messages_ru.properties
deleted file mode 100644
index 2a2269ae..00000000
--- a/juick-server/src/main/resources/messages_ru.properties
+++ /dev/null
@@ -1,78 +0,0 @@
-date.format=dd.MM.yyyy
-
-link.settings=Настройки
-link.returnToMain=Вернуться на главную
-link.contacts=Контакты
-link.tos=TOS
-
-link.popular=Популярные
-link.allMessages=Обзор
-link.withPhotos=Фото
-link.trends=Темы
-link.my=Моя лента
-link.privateMessages=Приватные
-link.discuss=Диалоги
-link.recommended=Рекомендации
-link.postMessage=Написать
-link.Login=Войти
-link.logout=Выйти
-
-link.settings.main=Главная
-link.settings.password=Пароль
-link.settings.about=О пользователе
-
-label.sponsor=Спонсор
-label.sponsors=Спонсоры
-label.search=Поиск
-label.register=Зарегистрироваться
-label.username=Имя пользователя
-label.password=Пароль
-
-postForm.newMessage=Новое сообщение...
-postForm.imageLink=Ссылка на изображение
-postForm.imageFormats=JPG/PNG, до 10Мб
-postForm.or=или
-postForm.upload=загрузить
-postForm.tags=Теги (через пробел)
-postForm.submit=Отправить
-
-message.recommend=Рекомендовать
-message.recommendedBy=♡ рекомендовали
-message.recommendedOthers=и еще {0}
-message.comment=Комментировать
-message.writeComment=Написать комментарий...
-message.share=Поделиться
-message.subscribe=Подписаться
-message.subscribed=Подписан
-message.delete=Удалить
-message.loginForSending=Чтобы добавлять сообщения и комментарии, <a href="{0}" class="a-login">представьтесь</a>
-message.sendLoginToXmpp=Отправьте <b>LOGIN</b> на <a href="xmpp:juick@juick.com?message;body=LOGIN">juick@juick.com</a>
-
-messages.next=Читать дальше
-
-reply.reply=Ответить
-reply.inReplyTo=в ответ на
-reply.replies=Ответы
-replies.showAsList=Показать списком
-replies.showAsTree=Показать деревом
-replies.unfoldAll=Раскрыть все
-
-question.areRegistered=Уже зарегистрированы?
-
-title.help=Справка
-title.loginOrSignup=Juick - Войдите в систему или зарегистрируйтесь
-title.index.anonym=Микроблоги Juick: популярные записи
-title.index.user=Популярные
-
-error.pageNotFound=Страница не найдена
-error.pageNotFound.description=Сожалеем, но страницу с этим адресом удалил её автор, либо её никогда не существовало.
-
-blog.blog=Блог
-blog.recommendations=Рекомендации
-blog.photos=Фотографии
-blog.iread=Я читаю
-blog.readers=Мои подписчики
-blog.bl=Черный список
-blog.messages=Сообщения
-blog.comments=Комментарии
-blog.allPostsWithTag=Все записи с тегом \ No newline at end of file
diff --git a/juick-server/src/main/resources/pg_schema_wip b/juick-server/src/main/resources/pg_schema_wip
deleted file mode 100644
index 61178495..00000000
--- a/juick-server/src/main/resources/pg_schema_wip
+++ /dev/null
@@ -1,1539 +0,0 @@
---
--- PostgreSQL database dump
---
-
-SET statement_timeout = 0;
-SET lock_timeout = 0;
-SET client_encoding = 'UTF8';
-SET standard_conforming_strings = off;
-SET check_function_bodies = false;
-SET client_min_messages = warning;
-SET escape_string_warning = off;
-
---
--- Name: juick; Type: SCHEMA; Schema: -; Owner: juick
---
-
-CREATE SCHEMA juick;
-
-
-ALTER SCHEMA juick OWNER TO juick;
-
---
--- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
---
-
-CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
-
-
---
--- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
---
-
-COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
-
-
-SET search_path = public, pg_catalog;
-
---
--- Name: auth_protocol; Type: TYPE; Schema: public; Owner: juick
---
-
-CREATE TYPE auth_protocol AS ENUM (
- 'xmpp',
- 'email',
- 'sms'
-);
-
-
-ALTER TYPE auth_protocol OWNER TO juick;
-
---
--- Name: messages_attach; Type: TYPE; Schema: public; Owner: juick
---
-
-CREATE TYPE messages_attach AS ENUM (
- 'jpg',
- 'mp4',
- 'png'
-);
-
-
-ALTER TYPE messages_attach OWNER TO juick;
-
---
--- Name: messages_lang; Type: TYPE; Schema: public; Owner: juick
---
-
-CREATE TYPE messages_lang AS ENUM (
- 'en',
- 'ru',
- 'fr',
- 'fa',
- '__'
-);
-
-
-ALTER TYPE messages_lang OWNER TO juick;
-
---
--- Name: replies_attach; Type: TYPE; Schema: public; Owner: juick
---
-
-CREATE TYPE replies_attach AS ENUM (
- 'jpg',
- 'mp4',
- 'png'
-);
-
-
-ALTER TYPE replies_attach OWNER TO juick;
-
---
--- Name: users_lang; Type: TYPE; Schema: public; Owner: juick
---
-
-CREATE TYPE users_lang AS ENUM (
- 'en',
- 'ru',
- 'fr',
- 'fa',
- '__'
-);
-
-
-ALTER TYPE users_lang OWNER TO juick;
-
-SET default_tablespace = '';
-
-SET default_with_oids = false;
-
---
--- Name: ads_messages; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE ads_messages (
- message_id bigint NOT NULL
-);
-
-
-ALTER TABLE ads_messages OWNER TO juick;
-
---
--- Name: ads_messages_log; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE ads_messages_log (
- user_id bigint NOT NULL,
- message_id bigint NOT NULL,
- ts bigint DEFAULT 0::bigint NOT NULL
-);
-
-
-ALTER TABLE ads_messages_log OWNER TO juick;
-
---
--- Name: android; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE android (
- user_id bigint NOT NULL,
- regid character varying(255) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE android OWNER TO juick;
-
---
--- Name: auth; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE auth (
- user_id bigint NOT NULL,
- protocol auth_protocol NOT NULL,
- account character varying(64) NOT NULL,
- authcode character varying(8) NOT NULL
-);
-
-
-ALTER TABLE auth OWNER TO juick;
-
---
--- Name: bl_tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE bl_tags (
- user_id bigint NOT NULL,
- tag_id bigint NOT NULL
-);
-
-
-ALTER TABLE bl_tags OWNER TO juick;
-
---
--- Name: bl_users; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE bl_users (
- user_id bigint NOT NULL,
- bl_user_id bigint NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE bl_users OWNER TO juick;
-
---
--- Name: captcha; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE captcha (
- jid character varying(64) NOT NULL,
- hash character varying(16) NOT NULL,
- confirmed smallint NOT NULL
-);
-
-
-ALTER TABLE captcha OWNER TO juick;
-
---
--- Name: captchaimg; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE captchaimg (
- id character varying(16) NOT NULL,
- txt character varying(6) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- ip character varying(16) NOT NULL
-);
-
-
-ALTER TABLE captchaimg OWNER TO juick;
-
---
--- Name: emails; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE emails (
- user_id bigint NOT NULL,
- email character varying(64) NOT NULL,
- subscr_hour smallint
-);
-
-
-ALTER TABLE emails OWNER TO juick;
-
---
--- Name: facebook; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE facebook (
- user_id bigint,
- fb_id numeric NOT NULL,
- loginhash character varying(36),
- access_token character varying(255),
- ts timestamp with time zone DEFAULT now() NOT NULL,
- fb_name character varying(64) NOT NULL,
- fb_link character varying(255) NOT NULL,
- crosspost boolean DEFAULT true NOT NULL
-);
-
-
-ALTER TABLE facebook OWNER TO juick;
-
---
--- Name: favorites; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE favorites (
- user_id bigint NOT NULL,
- message_id bigint NOT NULL,
- ts timestamp with time zone
-);
-
-
-ALTER TABLE favorites OWNER TO juick;
-
---
--- Name: friends_facebook; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE friends_facebook (
- user_id bigint NOT NULL,
- friend_id numeric NOT NULL
-);
-
-
-ALTER TABLE friends_facebook OWNER TO juick;
-
---
--- Name: images; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE images (
- mid bigint NOT NULL,
- rid bigint NOT NULL,
- thumb bigint NOT NULL,
- small bigint NOT NULL,
- medium bigint NOT NULL,
- height bigint NOT NULL,
- width bigint NOT NULL
-);
-
-
-ALTER TABLE images OWNER TO juick;
-
---
--- Name: ios; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE ios (
- user_id bigint NOT NULL,
- token character varying(64) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE ios OWNER TO juick;
-
---
--- Name: jids; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE jids (
- user_id bigint,
- jid character varying(64) NOT NULL,
- active smallint DEFAULT 0 NOT NULL,
- loginhash character varying(36),
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE jids OWNER TO juick;
-
---
--- Name: logins; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE logins (
- user_id bigint NOT NULL,
- hash character varying(16) NOT NULL
-);
-
-
-ALTER TABLE logins OWNER TO juick;
-
---
--- Name: mail; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE mail (
- user_id bigint NOT NULL,
- hash character varying(16) NOT NULL
-);
-
-
-ALTER TABLE mail OWNER TO juick;
-
---
--- Name: meon; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE meon (
- id bigint NOT NULL,
- user_id bigint NOT NULL,
- link character varying(255) NOT NULL,
- name character varying(32) NOT NULL,
- ico smallint
-);
-
-
-ALTER TABLE meon OWNER TO juick;
-
---
--- Name: meon_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE meon_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE meon_id_seq OWNER TO juick;
-
---
--- Name: meon_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE meon_id_seq OWNED BY meon.id;
-
-
---
--- Name: messages; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE messages (
- message_id bigint NOT NULL,
- user_id bigint NOT NULL,
- lang messages_lang DEFAULT '__'::messages_lang NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- replies smallint DEFAULT 0::smallint NOT NULL,
- maxreplyid smallint DEFAULT 0::smallint NOT NULL,
- privacy smallint DEFAULT 1::smallint NOT NULL,
- readonly boolean DEFAULT false NOT NULL,
- attach messages_attach,
- place_id bigint,
- lat numeric(10,7),
- lon numeric(10,7),
- popular smallint DEFAULT 0::smallint NOT NULL,
- hidden smallint DEFAULT 0::smallint NOT NULL,
- likes smallint DEFAULT 0::smallint NOT NULL
-);
-
-
-ALTER TABLE messages OWNER TO juick;
-
---
--- Name: messages_access; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE messages_access (
- message_id bigint NOT NULL,
- user_id bigint NOT NULL
-);
-
-
-ALTER TABLE messages_access OWNER TO juick;
-
---
--- Name: messages_message_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE messages_message_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE messages_message_id_seq OWNER TO juick;
-
---
--- Name: messages_message_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE messages_message_id_seq OWNED BY messages.message_id;
-
-
---
--- Name: messages_tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE messages_tags (
- message_id bigint NOT NULL,
- tag_id bigint NOT NULL
-);
-
-
-ALTER TABLE messages_tags OWNER TO juick;
-
---
--- Name: messages_txt; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE messages_txt (
- message_id bigint NOT NULL,
- tags text,
- repliesby text,
- txt text NOT NULL
-);
-
-
-ALTER TABLE messages_txt OWNER TO juick;
-
---
--- Name: messages_votes; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE messages_votes (
- message_id bigint NOT NULL,
- user_id bigint NOT NULL,
- vote smallint DEFAULT 1::smallint NOT NULL
-);
-
-
-ALTER TABLE messages_votes OWNER TO juick;
-
---
--- Name: places; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE places (
- place_id bigint NOT NULL,
- lat numeric(10,7) NOT NULL,
- lon numeric(10,7) NOT NULL,
- name character varying(64) NOT NULL,
- descr character varying(255),
- url character varying(128),
- user_id bigint NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE places OWNER TO juick;
-
---
--- Name: places_place_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE places_place_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE places_place_id_seq OWNER TO juick;
-
---
--- Name: places_place_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE places_place_id_seq OWNED BY places.place_id;
-
-
---
--- Name: places_tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE places_tags (
- place_id bigint NOT NULL,
- tag_id bigint NOT NULL
-);
-
-
-ALTER TABLE places_tags OWNER TO juick;
-
---
--- Name: pm; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE pm (
- user_id bigint NOT NULL,
- user_id_to bigint NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- txt text NOT NULL
-);
-
-
-ALTER TABLE pm OWNER TO juick;
-
---
--- Name: pm_inroster; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE pm_inroster (
- user_id bigint NOT NULL,
- jid character varying(64) NOT NULL
-);
-
-
-ALTER TABLE pm_inroster OWNER TO juick;
-
---
--- Name: pm_streams; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE pm_streams (
- user_id bigint NOT NULL,
- user_id_to bigint NOT NULL,
- lastmessage timestamp with time zone NOT NULL,
- lastview timestamp with time zone,
- unread smallint DEFAULT 0::smallint NOT NULL
-);
-
-
-ALTER TABLE pm_streams OWNER TO juick;
-
---
--- Name: presence; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE presence (
- user_id bigint NOT NULL,
- jid character varying(64),
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE presence OWNER TO juick;
-
---
--- Name: reader_links; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE reader_links (
- link_id bigint NOT NULL,
- rss_id bigint NOT NULL,
- url character varying(255) NOT NULL,
- title character varying(255) NOT NULL,
- ts timestamp with time zone NOT NULL
-);
-
-
-ALTER TABLE reader_links OWNER TO juick;
-
---
--- Name: reader_links_link_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE reader_links_link_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE reader_links_link_id_seq OWNER TO juick;
-
---
--- Name: reader_links_link_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE reader_links_link_id_seq OWNED BY reader_links.link_id;
-
-
---
--- Name: reader_rss; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE reader_rss (
- rss_id bigint NOT NULL,
- url character varying(255) NOT NULL,
- lastcheck timestamp with time zone NOT NULL
-);
-
-
-ALTER TABLE reader_rss OWNER TO juick;
-
---
--- Name: reader_rss_rss_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE reader_rss_rss_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE reader_rss_rss_id_seq OWNER TO juick;
-
---
--- Name: reader_rss_rss_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE reader_rss_rss_id_seq OWNED BY reader_rss.rss_id;
-
-
---
--- Name: replies; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE replies (
- message_id bigint NOT NULL,
- reply_id smallint NOT NULL,
- user_id bigint NOT NULL,
- replyto smallint DEFAULT 0::smallint NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- attach replies_attach,
- txt text NOT NULL
-);
-
-
-ALTER TABLE replies OWNER TO juick;
-
---
--- Name: sphinx; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE sphinx (
- counter_id smallint NOT NULL,
- max_id bigint NOT NULL
-);
-
-
-ALTER TABLE sphinx OWNER TO juick;
-
---
--- Name: subscr_messages; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE subscr_messages (
- message_id bigint NOT NULL,
- suser_id bigint NOT NULL
-);
-
-
-ALTER TABLE subscr_messages OWNER TO juick;
-
---
--- Name: subscr_tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE subscr_tags (
- tag_id bigint NOT NULL,
- suser_id bigint NOT NULL,
- jid character varying(64) NOT NULL,
- active boolean NOT NULL
-);
-
-
-ALTER TABLE subscr_tags OWNER TO juick;
-
---
--- Name: subscr_users; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE subscr_users (
- user_id bigint NOT NULL,
- suser_id bigint NOT NULL,
- jid character varying(64),
- active boolean NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE subscr_users OWNER TO juick;
-
---
--- Name: tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE tags (
- tag_id bigint NOT NULL,
- synonym_id bigint,
- name character varying(70),
- top boolean DEFAULT false NOT NULL,
- noindex boolean DEFAULT false NOT NULL,
- stat_messages bigint DEFAULT 0::bigint NOT NULL,
- stat_users smallint DEFAULT 0::smallint NOT NULL
-);
-
-
-ALTER TABLE tags OWNER TO juick;
-
---
--- Name: tags_ignore; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE tags_ignore (
- tag_id bigint NOT NULL
-);
-
-
-ALTER TABLE tags_ignore OWNER TO juick;
-
---
--- Name: tags_synonyms; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE tags_synonyms (
- name character varying(64) NOT NULL,
- changeto character varying(64) NOT NULL
-);
-
-
-ALTER TABLE tags_synonyms OWNER TO juick;
-
---
--- Name: tags_tag_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE tags_tag_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE tags_tag_id_seq OWNER TO juick;
-
---
--- Name: tags_tag_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE tags_tag_id_seq OWNED BY tags.tag_id;
-
-
---
--- Name: telegram; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE telegram (
- user_id bigint,
- tg_id numeric NOT NULL,
- tg_name character varying(64) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- loginhash character varying(36)
-);
-
-
-ALTER TABLE telegram OWNER TO juick;
-
---
--- Name: telegram_chats; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE telegram_chats (
- chat_id numeric
-);
-
-
-ALTER TABLE telegram_chats OWNER TO juick;
-
---
--- Name: top_ignore_messages; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE top_ignore_messages (
- message_id bigint NOT NULL
-);
-
-
-ALTER TABLE top_ignore_messages OWNER TO juick;
-
---
--- Name: top_ignore_tags; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE top_ignore_tags (
- tag_id bigint NOT NULL
-);
-
-
-ALTER TABLE top_ignore_tags OWNER TO juick;
-
---
--- Name: top_ignore_users; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE top_ignore_users (
- user_id bigint NOT NULL
-);
-
-
-ALTER TABLE top_ignore_users OWNER TO juick;
-
---
--- Name: twitter; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE twitter (
- user_id bigint NOT NULL,
- access_token character varying(64) NOT NULL,
- access_token_secret character varying(64) NOT NULL,
- uname character varying(64) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- crosspost boolean DEFAULT true NOT NULL
-);
-
-
-ALTER TABLE twitter OWNER TO juick;
-
---
--- Name: useroptions; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE useroptions (
- user_id bigint NOT NULL,
- jnotify boolean DEFAULT true NOT NULL,
- subscr_active boolean DEFAULT true NOT NULL,
- off_ts timestamp with time zone,
- xmppxhtml boolean DEFAULT false NOT NULL,
- subscr_notify boolean DEFAULT true NOT NULL,
- recommendations boolean DEFAULT true NOT NULL,
- privacy_view boolean DEFAULT true NOT NULL,
- privacy_reply boolean DEFAULT true NOT NULL,
- privacy_pm boolean DEFAULT true NOT NULL,
- repliesview boolean DEFAULT false NOT NULL
-);
-
-
-ALTER TABLE useroptions OWNER TO juick;
-
---
--- Name: users; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE users (
- id bigint NOT NULL,
- nick character varying(64) NOT NULL,
- passw character varying(32) NOT NULL,
- lang users_lang DEFAULT '__'::users_lang NOT NULL,
- banned smallint DEFAULT 0::smallint NOT NULL,
- lastmessage bigint DEFAULT 0::bigint NOT NULL,
- lastpm bigint DEFAULT 0::bigint NOT NULL,
- lastphoto bigint DEFAULT 0::bigint NOT NULL,
- karma smallint DEFAULT 0::smallint NOT NULL
-);
-
-
-ALTER TABLE users OWNER TO juick;
-
---
--- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: juick
---
-
-CREATE SEQUENCE users_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-
-ALTER TABLE users_id_seq OWNER TO juick;
-
---
--- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: juick
---
-
-ALTER SEQUENCE users_id_seq OWNED BY users.id;
-
-
---
--- Name: users_refs; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE users_refs (
- user_id bigint NOT NULL,
- ref bigint NOT NULL
-);
-
-
-ALTER TABLE users_refs OWNER TO juick;
-
---
--- Name: users_subscr; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE users_subscr (
- user_id bigint NOT NULL,
- cnt smallint DEFAULT 0::smallint NOT NULL
-);
-
-
-ALTER TABLE users_subscr OWNER TO juick;
-
---
--- Name: usersinfo; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE usersinfo (
- user_id bigint NOT NULL,
- jid character varying(32),
- fullname character varying(32),
- country character varying(32),
- url character varying(64),
- gender character varying(32),
- bday character varying(10),
- descr text
-);
-
-
-ALTER TABLE usersinfo OWNER TO juick;
-
---
--- Name: version; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE version (
- version numeric NOT NULL
-);
-
-
-ALTER TABLE version OWNER TO juick;
-
---
--- Name: vk; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE vk (
- user_id bigint,
- vk_id numeric NOT NULL,
- loginhash character varying(36),
- access_token character varying(128) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL,
- vk_name character varying(64) NOT NULL,
- vk_link character varying(64) NOT NULL,
- crosspost smallint DEFAULT 1::smallint NOT NULL
-);
-
-
-ALTER TABLE vk OWNER TO juick;
-
---
--- Name: winphone; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE winphone (
- user_id bigint NOT NULL,
- url character varying(255) NOT NULL,
- ts timestamp with time zone DEFAULT now() NOT NULL
-);
-
-
-ALTER TABLE winphone OWNER TO juick;
-
---
--- Name: wl_users; Type: TABLE; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE TABLE wl_users (
- user_id bigint NOT NULL,
- wl_user_id bigint NOT NULL
-);
-
-
-ALTER TABLE wl_users OWNER TO juick;
-
---
--- Name: id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY meon ALTER COLUMN id SET DEFAULT nextval('meon_id_seq'::regclass);
-
-
---
--- Name: message_id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY messages ALTER COLUMN message_id SET DEFAULT nextval('messages_message_id_seq'::regclass);
-
-
---
--- Name: place_id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY places ALTER COLUMN place_id SET DEFAULT nextval('places_place_id_seq'::regclass);
-
-
---
--- Name: link_id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY reader_links ALTER COLUMN link_id SET DEFAULT nextval('reader_links_link_id_seq'::regclass);
-
-
---
--- Name: rss_id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY reader_rss ALTER COLUMN rss_id SET DEFAULT nextval('reader_rss_rss_id_seq'::regclass);
-
-
---
--- Name: tag_id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY tags ALTER COLUMN tag_id SET DEFAULT nextval('tags_tag_id_seq'::regclass);
-
-
---
--- Name: id; Type: DEFAULT; Schema: public; Owner: juick
---
-
-ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass);
-
-
---
--- Name: idx_20438_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY images
- ADD CONSTRAINT idx_20438_primary PRIMARY KEY (mid, rid);
-
-
---
--- Name: idx_20453_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY mail
- ADD CONSTRAINT idx_20453_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20458_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY meon
- ADD CONSTRAINT idx_20458_primary PRIMARY KEY (id);
-
-
---
--- Name: idx_20483_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY messages
- ADD CONSTRAINT idx_20483_primary PRIMARY KEY (message_id);
-
-
---
--- Name: idx_20502_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY messages_txt
- ADD CONSTRAINT idx_20502_primary PRIMARY KEY (message_id);
-
-
---
--- Name: idx_20514_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY places
- ADD CONSTRAINT idx_20514_primary PRIMARY KEY (place_id);
-
-
---
--- Name: idx_20542_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY reader_links
- ADD CONSTRAINT idx_20542_primary PRIMARY KEY (link_id);
-
-
---
--- Name: idx_20551_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY reader_rss
- ADD CONSTRAINT idx_20551_primary PRIMARY KEY (rss_id);
-
-
---
--- Name: idx_20571_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY sphinx
- ADD CONSTRAINT idx_20571_primary PRIMARY KEY (counter_id);
-
-
---
--- Name: idx_20586_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY tags
- ADD CONSTRAINT idx_20586_primary PRIMARY KEY (tag_id);
-
-
---
--- Name: idx_20616_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY top_ignore_tags
- ADD CONSTRAINT idx_20616_primary PRIMARY KEY (tag_id);
-
-
---
--- Name: idx_20619_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY top_ignore_users
- ADD CONSTRAINT idx_20619_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20622_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY twitter
- ADD CONSTRAINT idx_20622_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20627_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY useroptions
- ADD CONSTRAINT idx_20627_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20653_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY users
- ADD CONSTRAINT idx_20653_primary PRIMARY KEY (id);
-
-
---
--- Name: idx_20663_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY usersinfo
- ADD CONSTRAINT idx_20663_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20672_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY users_subscr
- ADD CONSTRAINT idx_20672_primary PRIMARY KEY (user_id);
-
-
---
--- Name: idx_20694_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY wl_users
- ADD CONSTRAINT idx_20694_primary PRIMARY KEY (user_id, wl_user_id);
-
-
---
--- Name: idx_29418_primary; Type: CONSTRAINT; Schema: public; Owner: juick; Tablespace:
---
-
-ALTER TABLE ONLY bl_users
- ADD CONSTRAINT idx_29418_primary PRIMARY KEY (user_id, bl_user_id);
-
-
---
--- Name: idx_20390_regid; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20390_regid ON android USING btree (regid);
-
-
---
--- Name: idx_20390_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20390_user_id ON android USING btree (user_id);
-
-
---
--- Name: idx_20404_tag_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20404_tag_id ON bl_tags USING btree (tag_id);
-
-
---
--- Name: idx_20404_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20404_user_id ON bl_tags USING btree (user_id);
-
-
---
--- Name: idx_20418_email; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20418_email ON emails USING btree (email);
-
-
---
--- Name: idx_20421_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20421_user_id ON facebook USING btree (user_id);
-
-
---
--- Name: idx_20432_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20432_user_id ON friends_facebook USING btree (user_id, friend_id);
-
-
---
--- Name: idx_20441_token; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20441_token ON ios USING btree (token);
-
-
---
--- Name: idx_20441_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20441_user_id ON ios USING btree (user_id);
-
-
---
--- Name: idx_20445_jid; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20445_jid ON jids USING btree (jid);
-
-
---
--- Name: idx_20445_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20445_user_id ON jids USING btree (user_id);
-
-
---
--- Name: idx_20450_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20450_user_id ON logins USING btree (user_id);
-
-
---
--- Name: idx_20483_attach; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_attach ON messages USING btree (attach);
-
-
---
--- Name: idx_20483_hidden; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_hidden ON messages USING btree (hidden);
-
-
---
--- Name: idx_20483_place_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_place_id ON messages USING btree (place_id);
-
-
---
--- Name: idx_20483_popular; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_popular ON messages USING btree (popular);
-
-
---
--- Name: idx_20483_ts; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_ts ON messages USING btree (ts);
-
-
---
--- Name: idx_20483_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20483_user_id ON messages USING btree (user_id);
-
-
---
--- Name: idx_20496_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20496_message_id ON messages_access USING btree (message_id);
-
-
---
--- Name: idx_20499_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20499_message_id ON messages_tags USING btree (message_id);
-
-
---
--- Name: idx_20499_message_id_2; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20499_message_id_2 ON messages_tags USING btree (message_id, tag_id);
-
-
---
--- Name: idx_20499_tag_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20499_tag_id ON messages_tags USING btree (tag_id);
-
-
---
--- Name: idx_20508_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20508_message_id ON messages_votes USING btree (message_id, user_id);
-
-
---
--- Name: idx_20529_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20529_user_id ON pm_inroster USING btree (user_id);
-
-
---
--- Name: idx_20529_user_id_2; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20529_user_id_2 ON pm_inroster USING btree (user_id, jid);
-
-
---
--- Name: idx_20532_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20532_user_id ON pm_streams USING btree (user_id, user_id_to);
-
-
---
--- Name: idx_20536_jid; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20536_jid ON presence USING btree (jid);
-
-
---
--- Name: idx_20563_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20563_message_id ON replies USING btree (message_id);
-
-
---
--- Name: idx_20563_ts; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20563_ts ON replies USING btree (ts);
-
-
---
--- Name: idx_20563_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20563_user_id ON replies USING btree (user_id);
-
-
---
--- Name: idx_20574_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20574_message_id ON subscr_messages USING btree (message_id, suser_id);
-
-
---
--- Name: idx_20577_tag_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20577_tag_id ON subscr_tags USING btree (tag_id, suser_id);
-
-
---
--- Name: idx_20580_suser_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20580_suser_id ON subscr_users USING btree (suser_id);
-
-
---
--- Name: idx_20580_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20580_user_id ON subscr_users USING btree (user_id, suser_id);
-
-
---
--- Name: idx_20586_synonym_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20586_synonym_id ON tags USING btree (synonym_id);
-
-
---
--- Name: idx_20607_chat_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20607_chat_id ON telegram_chats USING btree (chat_id);
-
-
---
--- Name: idx_20627_recommendations; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20627_recommendations ON useroptions USING btree (recommendations);
-
-
---
--- Name: idx_20653_nick; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20653_nick ON users USING btree (nick);
-
-
---
--- Name: idx_20669_ref; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20669_ref ON users_refs USING btree (ref);
-
-
---
--- Name: idx_20682_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20682_user_id ON vk USING btree (user_id);
-
-
---
--- Name: idx_20690_url; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_20690_url ON winphone USING btree (url);
-
-
---
--- Name: idx_20690_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_20690_user_id ON winphone USING btree (user_id);
-
-
---
--- Name: idx_29422_message_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_29422_message_id ON favorites USING btree (message_id);
-
-
---
--- Name: idx_29422_user_id; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE INDEX idx_29422_user_id ON favorites USING btree (user_id);
-
-
---
--- Name: idx_29422_user_id_2; Type: INDEX; Schema: public; Owner: juick; Tablespace:
---
-
-CREATE UNIQUE INDEX idx_29422_user_id_2 ON favorites USING btree (user_id, message_id);
-
-
---
--- Name: public; Type: ACL; Schema: -; Owner: postgres
---
-
-REVOKE ALL ON SCHEMA public FROM PUBLIC;
-REVOKE ALL ON SCHEMA public FROM postgres;
-GRANT ALL ON SCHEMA public TO postgres;
-GRANT ALL ON SCHEMA public TO PUBLIC;
-
-
---
--- PostgreSQL database dump complete
---
-
diff --git a/juick-server/src/main/resources/rome.properties b/juick-server/src/main/resources/rome.properties
deleted file mode 100644
index fdb9aaa2..00000000
--- a/juick-server/src/main/resources/rome.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-rss_2.0.item.ModuleParser.classes=com.juick.server.api.rss.extension.JuickModuleParser
-rss_2.0.item.ModuleGenerator.classes=com.juick.server.api.rss.extension.JuickModuleGenerator \ No newline at end of file
diff --git a/juick-server/src/main/resources/schema.sql b/juick-server/src/main/resources/schema.sql
deleted file mode 100644
index 2e8fad9b..00000000
--- a/juick-server/src/main/resources/schema.sql
+++ /dev/null
@@ -1,396 +0,0 @@
-SET DB_CLOSE_ON_EXIT TRUE;
-
-CREATE TABLE IF NOT EXISTS `android` (
- `user_id` int(10) unsigned NOT NULL,
- `regid` char(255) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-);
-CREATE TABLE IF NOT EXISTS `auth` (
- `user_id` int(10) unsigned NOT NULL,
- `protocol` enum('xmpp','email','sms') NOT NULL,
- `account` char(64) NOT NULL,
- `authcode` char(8) NOT NULL
-);
-CREATE TABLE IF NOT EXISTS `bl_tags` (
- `user_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL,
-);
-CREATE TABLE IF NOT EXISTS `bl_users` (
- `user_id` int(10) unsigned NOT NULL,
- `bl_user_id` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`user_id`,`bl_user_id`)
-);
-CREATE TABLE IF NOT EXISTS `facebook` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `fb_id` bigint(20) unsigned NULL,
- `loginhash` char(36) DEFAULT NULL,
- `access_token` char(255) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `fb_name` char(64) NULL,
- `fb_link` char(255) NULL,
- `crosspost` tinyint(1) unsigned NOT NULL DEFAULT '1'
-);
-
-CREATE TABLE IF NOT EXISTS `reactions` (
- `like_id` int(10) unsigned NOT NULL,
- `description` varchar (100) NOT NULL
-);
-CREATE TABLE IF NOT EXISTS `favorites` (
- `user_id` int(10) unsigned NOT NULL,
- `message_id` int(10) unsigned NOT NULL,
- `ts` datetime NOT NULL,
- `like_id` int(10),
- foreign key (like_id) references reactions(like_id)
-);
-
-
-
-CREATE TABLE IF NOT EXISTS `friends_facebook` (
- `user_id` int(10) unsigned NOT NULL,
- `friend_id` bigint(20) unsigned NOT NULL,
- UNIQUE KEY `user_id` (`user_id`,`friend_id`)
-);
-CREATE TABLE IF NOT EXISTS `images` (
- `mid` int(10) unsigned NOT NULL,
- `rid` int(10) unsigned NOT NULL,
- `thumb` int(10) unsigned NOT NULL,
- `small` int(10) unsigned NOT NULL,
- `medium` int(10) unsigned NOT NULL,
- `height` int(10) unsigned NOT NULL,
- `width` int(10) unsigned NOT NULL,
- PRIMARY KEY (`mid`,`rid`)
-);
-
-CREATE TABLE IF NOT EXISTS `mail` (
- `user_id` int(10) unsigned NOT NULL,
- `hash` char(16) NOT NULL,
- PRIMARY KEY (`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `meon` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `user_id` int(10) unsigned NOT NULL,
- `link` char(255) NOT NULL,
- `name` char(32) NOT NULL,
- `ico` smallint(5) unsigned DEFAULT NULL,
- PRIMARY KEY (`id`)
-);
-
-
-
-CREATE TABLE IF NOT EXISTS `messages_access` (
- `message_id` int(10) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `messages_tags` (
- `message_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL,
- UNIQUE KEY `message_id_2` (`message_id`,`tag_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `messages_txt` (
- `message_id` int(10) unsigned NOT NULL,
- `tags` varchar(255) DEFAULT NULL,
- `repliesby` varchar(96) DEFAULT NULL,
- `txt` mediumtext NOT NULL,
- PRIMARY KEY (`message_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `messages_votes` (
- `message_id` int(10) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `vote` tinyint(4) NOT NULL DEFAULT '1',
- UNIQUE KEY `message_id` (`message_id`,`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `messenger` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `sender_id` bigint(20) NOT NULL,
- `display_name` char(64) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `loginhash` char(36) DEFAULT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `places` (
- `place_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `lat` decimal(10,7) NOT NULL,
- `lon` decimal(10,7) NOT NULL,
- `name` char(64) NOT NULL,
- `descr` char(255) DEFAULT NULL,
- `url` char(128) DEFAULT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`place_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `places_tags` (
- `place_id` int(10) unsigned NOT NULL,
- `tag_id` int(10) unsigned NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `pm` (
- `user_id` int(10) unsigned NOT NULL,
- `user_id_to` int(10) unsigned NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `txt` text NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `pm_streams` (
- `user_id` int(10) unsigned NOT NULL,
- `user_id_to` int(10) unsigned NOT NULL,
- `lastmessage` datetime NOT NULL,
- `lastview` datetime DEFAULT NULL,
- `unread` smallint(5) unsigned NOT NULL DEFAULT '0',
- UNIQUE KEY (`user_id`,`user_id_to`)
-);
-
-CREATE TABLE IF NOT EXISTS `presence` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(64) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY (`jid`)
-);
-
-CREATE TABLE IF NOT EXISTS `replies` (
- `message_id` int(10) unsigned NOT NULL,
- `reply_id` smallint(5) unsigned NOT NULL,
- `user_id` int(10) unsigned NOT NULL,
- `replyto` smallint(5) unsigned NOT NULL DEFAULT '0',
- `ts` timestamp(9) NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `attach` nchar(3) check (attach in ('jpg', 'mp4', 'png')),
- `txt` mediumtext NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `subscr_messages` (
- `message_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- `last_read_rid` smallint(5) unsigned NOT NULL DEFAULT '0',
- UNIQUE KEY (`message_id`,`suser_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `subscr_tags` (
- `tag_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- UNIQUE KEY (`tag_id`,`suser_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `subscr_users` (
- `user_id` int(10) unsigned NOT NULL,
- `suser_id` int(10) unsigned NOT NULL,
- `jid` char(64) DEFAULT NULL,
- `active` bit(1) NOT NULL DEFAULT TRUE,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY (`user_id`,`suser_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `tags` (
- `tag_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `synonym_id` int(10) unsigned DEFAULT NULL,
- `name` varchar_ignorecase(70) DEFAULT NULL,
- `top` tinyint(1) unsigned NOT NULL DEFAULT '0',
- `noindex` tinyint(1) unsigned NOT NULL DEFAULT '0',
- `stat_messages` int(10) unsigned NOT NULL DEFAULT '0',
- `stat_users` smallint(5) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`tag_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `tags_ignore` (
- `tag_id` int(10) unsigned NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `tags_synonyms` (
- `name` char(64) NOT NULL,
- `changeto` char(64) NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `telegram` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `tg_id` bigint(20) NOT NULL,
- `tg_name` char(64) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `loginhash` char(36) DEFAULT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `telegram_chats` (
- `chat_id` bigint(20) DEFAULT NULL,
- UNIQUE KEY `chat_id` (`chat_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `top_ignore_messages` (
- `message_id` int(10) unsigned NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `top_ignore_tags` (
- `tag_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`tag_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `top_ignore_users` (
- `user_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `twitter` (
- `user_id` int(10) unsigned NOT NULL,
- `access_token` char(64) NOT NULL,
- `access_token_secret` char(64) NOT NULL,
- `uname` char(64) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `crosspost` tinyint(1) unsigned NOT NULL DEFAULT '1',
- PRIMARY KEY (`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `useroptions` (
- `user_id` int(10) unsigned NOT NULL,
- `jnotify` tinyint(1) NOT NULL DEFAULT '1',
- `subscr_active` tinyint(1) NOT NULL DEFAULT '1',
- `off_ts` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `xmppxhtml` tinyint(1) NOT NULL DEFAULT '0',
- `subscr_notify` tinyint(1) NOT NULL DEFAULT '1',
- `recommendations` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_view` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_reply` tinyint(1) NOT NULL DEFAULT '1',
- `privacy_pm` tinyint(1) NOT NULL DEFAULT '1',
- `repliesview` tinyint(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `users` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `nick` char(64) NOT NULL,
- `passw` char(32) NOT NULL,
- `lang` enum('en','ru','fr','fa','__') NOT NULL DEFAULT '__',
- `banned` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `lastmessage` timestamp(9) NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `lastpm` int(11) NOT NULL DEFAULT '0',
- `lastphoto` int(11) NOT NULL DEFAULT '0',
- `karma` smallint(6) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`),
- UNIQUE KEY `nick` (`nick`)
-);
-
-CREATE TABLE IF NOT EXISTS `users_refs` (
- `user_id` int(10) unsigned NOT NULL,
- `ref` int(10) unsigned NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `users_subscr` (
- `user_id` int(10) unsigned NOT NULL,
- `cnt` smallint(5) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`user_id`)
-);
-
-CREATE TABLE IF NOT EXISTS `usersinfo` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(32) DEFAULT NULL,
- `fullname` char(32) DEFAULT NULL,
- `country` char(32) DEFAULT NULL,
- `url` char(64) DEFAULT NULL,
- `gender` char(32) DEFAULT NULL,
- `bday` char(10) DEFAULT NULL,
- `descr` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`user_id`)
-);
-CREATE TABLE IF NOT EXISTS `emails` (
- `user_id` int(10) unsigned NOT NULL,
- `email` char(64) NOT NULL PRIMARY KEY,
- `subscr_hour` tinyint(4) DEFAULT NULL,
- foreign key (user_id) references users(id)
-);
-CREATE TABLE IF NOT EXISTS `ios` (
- `user_id` int(10) unsigned NOT NULL,
- `token` char(64) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `token` (`token`),
- foreign key (user_id) references users(id)
-);
-
-CREATE TABLE IF NOT EXISTS `jids` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `jid` char(64) NOT NULL,
- `active` tinyint(1) NOT NULL DEFAULT '1',
- `loginhash` char(36) DEFAULT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY `jid` (`jid`),
- foreign key (user_id) references users(id)
-);
-
-CREATE TABLE IF NOT EXISTS `logins` (
- `user_id` int(10) unsigned NOT NULL,
- `hash` char(16) NOT NULL,
- UNIQUE KEY (`user_id`)
-);
-CREATE TABLE IF NOT EXISTS `messages` (
- `message_id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
- `user_id` int(10) unsigned NOT NULL,
- `lang` enum('en','ru','fr','fa','__') NOT NULL DEFAULT '__',
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `replies` smallint(5) unsigned NOT NULL DEFAULT '0',
- `maxreplyid` smallint(5) unsigned NOT NULL DEFAULT '0',
- `privacy` tinyint(4) NOT NULL DEFAULT '1',
- `readonly` tinyint(1) NOT NULL DEFAULT '0',
- `attach` nchar(3) check (attach in ('jpg', 'mp4', 'png')),
- `place_id` int(10) unsigned DEFAULT NULL,
- `lat` decimal(10,7) DEFAULT NULL,
- `lon` decimal(10,7) DEFAULT NULL,
- `popular` tinyint(4) NOT NULL DEFAULT '0',
- `hidden` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `likes` smallint(6) NOT NULL DEFAULT '0',
- `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- FOREIGN KEY (`user_id`) references users(id)
-);
-CREATE TABLE IF NOT EXISTS `pm_inroster` (
- `user_id` int(10) unsigned NOT NULL,
- `jid` char(64) NOT NULL,
- UNIQUE KEY (`user_id`,`jid`),
- FOREIGN KEY (`user_id`) references users(id)
-);
-
-CREATE TABLE IF NOT EXISTS `version` (
- `version` bigint(20) NOT NULL
-);
-
-CREATE TABLE IF NOT EXISTS `vk` (
- `user_id` int(10) unsigned DEFAULT NULL,
- `vk_id` bigint(20) NOT NULL,
- `loginhash` char(36) DEFAULT NULL,
- `access_token` char(128) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `vk_name` char(64) NOT NULL,
- `vk_link` char(64) NOT NULL,
- `crosspost` bit(1) unsigned NOT NULL DEFAULT FALSE,
- FOREIGN KEY (`user_id`) references users(id)
-);
-
-CREATE TABLE IF NOT EXISTS `winphone` (
- `user_id` int(10) unsigned NOT NULL,
- `url` char(255) NOT NULL,
- `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- UNIQUE KEY (`url`),
- FOREIGN KEY (`user_id`) references users(id)
-);
-
-CREATE TABLE IF NOT EXISTS `wl_users` (
- `user_id` int(10) unsigned NOT NULL,
- `wl_user_id` int(10) unsigned NOT NULL,
- PRIMARY KEY (`user_id`,`wl_user_id`)
-);
-
-CREATE CACHED TABLE PUBLIC."flyway_schema_history" (
- "installed_rank" INT NOT NULL,
- "version" VARCHAR(50),
- "description" VARCHAR(200) NOT NULL,
- "type" VARCHAR(20) NOT NULL,
- "script" VARCHAR(1000) NOT NULL,
- "checksum" INT,
- "installed_by" VARCHAR(100) NOT NULL,
- "installed_on" TIMESTAMP DEFAULT CURRENT_TIMESTAMP() NOT NULL,
- "execution_time" INT NOT NULL,
- "success" BOOLEAN NOT NULL
-);
-ALTER TABLE PUBLIC."flyway_schema_history" ADD CONSTRAINT PUBLIC."flyway_schema_history_pk" PRIMARY KEY("installed_rank");
--- 1 +/- SELECT COUNT(*) FROM PUBLIC."flyway_schema_history";
-INSERT INTO PUBLIC."flyway_schema_history"("installed_rank", "version", "description", "type", "script", "checksum", "installed_by", "installed_on", "execution_time", "success") VALUES
-(1, '1', '<< Flyway Baseline >>', 'BASELINE', '<< Flyway Baseline >>', NULL, 'SA', TIMESTAMP '2018-08-14 13:05:13.724', 0, TRUE); \ No newline at end of file
diff --git a/juick-server/src/main/resources/static/favicon.png b/juick-server/src/main/resources/static/favicon.png
deleted file mode 100644
index bc7161e2..00000000
--- a/juick-server/src/main/resources/static/favicon.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/static/logo.png b/juick-server/src/main/resources/static/logo.png
deleted file mode 100644
index 933f6099..00000000
--- a/juick-server/src/main/resources/static/logo.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/static/tagscloud.png b/juick-server/src/main/resources/static/tagscloud.png
deleted file mode 100644
index 3e1bf169..00000000
--- a/juick-server/src/main/resources/static/tagscloud.png
+++ /dev/null
Binary files differ
diff --git a/juick-server/src/main/resources/templates/layouts/content.html b/juick-server/src/main/resources/templates/layouts/content.html
deleted file mode 100644
index d2d29c4e..00000000
--- a/juick-server/src/main/resources/templates/layouts/content.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<html prefix="og: http://ogp.me/ns#">
-<head>
- <meta charset="utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
- <script type="text/javascript" src="{{ beans.webApp.scriptsUrl }}"></script>
- <link rel="stylesheet" type="text/css" href="{{ beans.webApp.styleUrl }}"/>
- {% block headers %}
- {{ headers | default('') | raw }}
- {% endblock %}
- <title>{{ title | default('Juick') }}</title>
- <meta property="og:type" content="{{ ogtype | default('website') }}" />
- <meta property="fb:app_id" content="130568668304" />
- <meta name="viewport" content="width=device-width,initial-scale=1"/>
- <meta name="msapplication-config" content="//i.juick.com/browserconfig.xml"/>
- <meta name="msapplication-TileColor" content="#ffffff"/>
- <meta name="msapplication-TileImage" content="//i.juick.com/ms-icon-144x144.png"/>
- <meta name="theme-color" content="#ffffff"/>
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <link rel="apple-touch-icon" sizes="57x57" href="//i.juick.com/apple-icon-57x57.png"/>
- <link rel="apple-touch-icon" sizes="60x60" href="//i.juick.com/apple-icon-60x60.png"/>
- <link rel="apple-touch-icon" sizes="72x72" href="//i.juick.com/apple-icon-72x72.png"/>
- <link rel="apple-touch-icon" sizes="76x76" href="//i.juick.com/apple-icon-76x76.png"/>
- <link rel="apple-touch-icon" sizes="114x114" href="//i.juick.com/apple-icon-114x114.png"/>
- <link rel="apple-touch-icon" sizes="120x120" href="//i.juick.com/apple-icon-120x120.png"/>
- <link rel="apple-touch-icon" sizes="144x144" href="//i.juick.com/apple-icon-144x144.png"/>
- <link rel="apple-touch-icon" sizes="152x152" href="//i.juick.com/apple-icon-152x152.png"/>
- <link rel="apple-touch-icon" sizes="180x180" href="//i.juick.com/apple-icon-180x180.png"/>
- <link rel="icon" type="image/png" sizes="32x32" href="//i.juick.com/favicon-32x32.png"/>
- <link rel="icon" type="image/png" sizes="96x96" href="//i.juick.com/favicon-96x96.png"/>
- <link rel="icon" type="image/png" sizes="16x16" href="//i.juick.com/favicon-16x16.png"/>
- <link rel="manifest" href="//i.juick.com/manifest.json"/>
-</head>
-<body id="body" {% if visitor.uid > 0 %}data-hash="{{visitor.authHash}}"{% endif %}>
-{% block body %}
-{% endblock %}
-</body>
-</html>
diff --git a/juick-server/src/main/resources/templates/layouts/default.html b/juick-server/src/main/resources/templates/layouts/default.html
deleted file mode 100644
index 343885c4..00000000
--- a/juick-server/src/main/resources/templates/layouts/default.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "layouts/content" %}
-{% block body %}
-{% include "views/partial/navigation" %}
-<div id="wrapper">
- <section id="content"
- {% if msg | default('') is not empty %}data-mid="{{ msg.mid }}"{% endif %}>
- {% block content %}
- {% endblock %}
- </section>
- <aside id="column">
- {% block column %}
- {% endblock %}
- </aside>
-</div>
-{% include "views/partial/footer" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/layouts/minimal.html b/juick-server/src/main/resources/templates/layouts/minimal.html
deleted file mode 100644
index 15924521..00000000
--- a/juick-server/src/main/resources/templates/layouts/minimal.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{% extends "layouts/content" %}
-{% block body %}
-<div id="wrapper">
- <section id="minimal_content">
- {% block content %}
- {% endblock %}
- </section>
-</div>
-{% include "views/partial/footer" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/layouts/note.html b/juick-server/src/main/resources/templates/layouts/note.html
deleted file mode 100644
index 42b939c0..00000000
--- a/juick-server/src/main/resources/templates/layouts/note.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% import "views/macros/tags" %}
-<p>{{ msg | formatMessage }}</p>
-{% if msg.tags.size > 0 %}
-<div class="msg-tags">{{ allTags(baseUri, msg.tags | tagsList) }}</div>
-{% endif %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/404.html b/juick-server/src/main/resources/templates/views/404.html
deleted file mode 100644
index 02a790e6..00000000
--- a/juick-server/src/main/resources/templates/views/404.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
- <article>
- <h1>Страница не найдена</h1>
- <p>Сожалеем, но страницу с этим адресом удалил её автор, либо её никогда не существовало.</p>
- </article>
-{% endblock %}
-
-{% block "column" %}
-{% include "views/partial/homecolumn" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/blog.html b/juick-server/src/main/resources/templates/views/blog.html
deleted file mode 100644
index 91decad6..00000000
--- a/juick-server/src/main/resources/templates/views/blog.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{% extends "layouts/default" %}
-{% import "views/macros/tags" %}
-{% block content %}
-{% if noindex %}
-<!--noindex-->
-{% endif %}
-{% if paramTag | default('') is not empty %}
-<p class="page"><a href="/tag/{{ paramTag.name | urlencode }}">← {{ i18n("messages","blog.allPostsWithTag") }} <b>{{ paramTag.name | escape }}</b></a></p>
-{% endif %}
-<div>
-{% for msg in msgs %}
-{% include "views/partial/message" %}
-{% endfor %}
-</div>
-{% if nextpage | default('') is not empty %}
-<p class="page"><a href="{{ nextpage | raw }}" rel="prev">{{ i18n("messages","messages.next") }} →</a></p>
-{% endif %}
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% if noindex %}
-<!--/noindex-->
-{% endif %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/blog_tags.html b/juick-server/src/main/resources/templates/views/blog_tags.html
deleted file mode 100644
index 48e517eb..00000000
--- a/juick-server/src/main/resources/templates/views/blog_tags.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{% extends "layouts/default" %}
-{% import "views/macros/tags" %}
-{% block content %}
-<p>
- {{ tags(user.name, tags) }}
-</p>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/help.html b/juick-server/src/main/resources/templates/views/help.html
deleted file mode 100644
index 3a022497..00000000
--- a/juick-server/src/main/resources/templates/views/help.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- {{ content | raw }}
-</article>
-{% endblock %}
-
-{% block "column" %}
-{{ navigation | raw }}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/index.html b/juick-server/src/main/resources/templates/views/index.html
deleted file mode 100644
index 97d726de..00000000
--- a/juick-server/src/main/resources/templates/views/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{% extends "layouts/default" %}
-{% import "views/macros/tags" %}
-{% block content %}
-{% if noindex %}
-<!--noindex-->
-{% endif %}
-{% for msg in msgs %}
-{% include "views/partial/message" %}
-{% endfor %}
-{% if nextpage | default('') is not empty %}
-<p class="page"><a href="{{ nextpage | raw }}" rel="prev">{{ i18n("messages","messages.next") }} →</a></p>
-{% endif %}
-{% endblock %}
-{% block "column" %}
-{% if tag | default('') is not empty %}
-{% include "views/partial/tagcolumn" %}
-{% elseif visitor.uid > 0 %}
-{% if discover %}
-{% include "views/partial/homecolumn" %}
-{% else %}
-{% include "views/partial/usercolumn" %}
-{% endif %}
-{% else %}
-{% include "views/partial/homecolumn" %}
-{% endif %}
-{% if noindex %}
-<!--/noindex-->
-{% endif %}
-{% endblock %}
diff --git a/juick-server/src/main/resources/templates/views/login.html b/juick-server/src/main/resources/templates/views/login.html
deleted file mode 100644
index a538cb26..00000000
--- a/juick-server/src/main/resources/templates/views/login.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Juick</title>
- <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js" defer="defer"></script>
- <style>
- * { margin: 0; padding: 0; }
- html { font-family: sans-serif; font-size: 12pt; }
- html { background: #f8f8f8; }
- body { margin: 100px auto 0 auto; width: 1000px; }
- a { color: #069; }
- ul { float: left; width: 700px; height: 350px; list-style-type: none; background: url(/tagscloud.png) no-repeat; position: relative; box-shadow: 0 0 3px rgba(0,0,0,.16); }
- ul a { position: absolute; display: block; text-indent: 100%; white-space: nowrap; overflow: hidden; }
-
- #bottom1 { position: absolute; left: 0px; bottom: 10px; width: 100%; text-align: center; color: #555; }
- #bottom2 { position: absolute; left: 0px; bottom: -50px; width: 100%; padding-bottom: 20px; text-align: center; font-size: small; color: #777; }
-
- #signup,#signin { margin-left: 730px; width: 250px; }
- #signup { padding-top: 25px; }
- #signup>div { width: 100%; margin: 15px 0; }
- #signup>div>a { display: block; width: 100%; height: 32px; line-height: 32px; text-indent: 37px; text-decoration: none; overflow: hidden; }
-
- #facebook a { color: #FFF; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAADNQTFRFO1edX3ewl6bLnKrOoK3QrrrYvMXe2N7r3OLu3+Tv5urz7O/29vf6+Pn7+vv9/Pz9////ykQjsQAAAEZJREFUOMtjYBgFuAATO68ADxdOaUYuATDAqYBbAL8CFgECCjiBcqz4XMiPz3oQEKCtAgEkwEdIAQchBWyEFDAPkDdHsAIAhZkIwz/VK/UAAAAASUVORK5CYII=") no-repeat #3A569C; }
- #vk a { color: #FFF; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAHJQTFRFbY+zbo+zbpCzb5C0cpO1c5O2dZW3dpa4e5m6gJ29gZ69lq/In7bNo7jPrcDUs8XXvs3dv87dy9fkztnlz9rm0Nrm093o1N7o1+Dq3OTt3ubu4Ofv5Orw7fH27vL28PP38vX49Pb5+vv8+/z9/Pz9////2jSYlQAAAG5JREFUOMvtkEcOgDAMBE3vvXdIyP+/iMMRKfYHmMtcRtE6AD8f1Is8pyKgAs0RGYO2HSWqMQaoBHVRgYsS3AsrtyFlrqgdJlCLb95gxQO6IkZCqL+KCjz0TQU5ejOf2a3aJXPF7BOB2PvMhp8PDzGRFgEe7xvEAAAAAElFTkSuQmCC") no-repeat #6d8fb3; }
- #xmpp>a { color: #333; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAt9QTFRFBj5rCUFoFz5mDEFuDUNqGUJkGUNgAEprEkVtGkRhHURnHEZjAE+BIElmEEx/HEx0PUdTHE5wMEtfO0laJk5sFlN6Nk1cKFBuIlJ1R0pYRExTGF2KMVh1OFhxDGSQT1deNlx6TVhkIGKPUlphKWOFU1tiOmB+Vl1kmlAuNmaDQGpaIG6ba2Q2SGeBN2uUNW+LF3mGRmyLV3BAL3xWgmVJ2VAa2lEb0VYX11UafWlmam9mam5xy1km3lUea29y2VccvF8obHBz21gd4VcXS3ebPoVG1lwl5FkaU3iYYHaH2F0ejHFIx2Iv4V0aP4o+02As218g4l4bPYtFX351KZFaymU43mIrVYoz5mEfT4w0xGsrSo82eXqDw2s+z2k1OZVAT4SoPZU5RZM4NJVYbYc8VoSiWY43WItbuXBK52gYOI20TpM6YYSYfX98T5Q7foB9aYSZSZc8Ro21cYxH7GwdT46e0HFGeopO2HA8V5ZEf4s8528l1HM7UJs5UI+xXoyrWZhGY4ylyHdMwXhXQZS7XpdNU5tH4XJBYJZZcIuhbpJk0HdPU588kohqOZ2pVZS30XpX6XcxSaFrz4FIUqVWWqVCYZm23YBGxYRrZZ2QXpy/5YFC7IA+6oBRb6ZUcKZn44ZSgKJu54hHmJqXbbBNfKh3cq5nYqrMpJyVdrBjx5WCo56diamAjaWdyZeE8JFV8ZJWnqOlaK/Sd7Zh7pVdgbN6x52N8JdfwqCU8ZhgZLbXb7a5grtTmK+UxKKWtqahq6qhd7bHqauop6yvqqyp755pbbzRrK6rwamgib53qq+xra+sobSg86Jza8PJsLKujMVctrGwqLapv7Crr7Wr8ad1srSxj8R9uLOys7WyubSztLazkcZ/sre6tbe0r7m0tri1t7m2vri3uLq3v7m4ubu4nc9mpNBvos2UptJxtNWXtteFuNmbuNyQud2Rut6SwN+aweCbwuGdw+KeweKkF4OfHQAAAadJREFUOMtjeEoAMAwfBQ9vYJO68RCu4BYDq1bXmr2XHoMlnlzet2qGpTgX8y2EFWwensEdrW2FbUAlJ2zDKsqaYwo6eZHcIGzoor/s5IdPSfefPt3nf3Xn3HZpPU8xJAXWIvU88VOffcm78vTptrijJe4OfAmy1kgKzjMlaIfUPvvQcObp03U120ucTZQaGc8je1NZrd8g8cL7eUufPp0wfX2mvVydripKONzkTG1JXvL6TuXTR/Zb5gR6F+Vw30QNqNUss/pqn3/MvrTD7Wy1V9Y0jtXoIZnLv2nSnrfzF3bP3hDRu1wwHzOo1VWOTXn5yi/q7MTJuxTUscTFQyHNc5vfbU1btOCgjNBDbJH1UF5i9/XP6VVrJRUfYo/Nx3YcpS/euOo4Pn6MqeDx44f3LoY2SYnOXBlUfPPug8cwRQxQ6Qf39sda+HqZaQiwGydFlx+4eQ+qAqrg4b3bPqbmNhkrNm5cbGUUHply7d6Dh8hWPH744Oa186eOHDl06NDh46fP33zwEMUEiCMe3L13GwjuPbj38PHTx9jT5OPHj5G9MFQyDgA8riWAv9eLFAAAAABJRU5ErkJggg==") no-repeat #BBB; }
- #xmppinfo { background: #FFF; padding: 10px; display: none; }
-
- #signin { text-align: center; font-size: small; }
- #signinform { background: #FFF; padding: 10px 15px; margin-top: 15px; display: none; }
- input.txt { width: 212px; border: 1px solid #CCC; margin: 3px 0; padding: 3px; }
- input.submit { width: 70px; border: 1px solid #CCC; margin: 3px 0; padding: 3px; }
- </style>
- <link rel="icon" href="//i.juick.com/favicon.png"/>
- </head>
-
-<body>
-
-<ul id="tags">
- <li><a href="/tag/juick" style="left: 359px; top: 120px; width: 311px; height: 99px">juick</a></li>
- <li><a href="/tag/linux" style="left: 201px; top: 100px; width: 98px; height: 35px">linux</a></li>
- <li><a href="/tag/android" style="left: 314px; top: 42px; width: 45px; height: 158px">android</a></li>
- <li><a href="/tag/работа" style="left: 149px; top: 138px; width: 165px; height: 41px">работа</a></li>
- <li><a href="/tag/music" style="left: 119px; top: 249px; width: 124px; height: 32px">music</a></li>
- <li><a href="/tag/windows" style="left: 448px; top: 234px; width: 186px; height: 32px">windows</a></li>
- <li><a href="/tag/google" style="left: 244px; top: 252px; width: 134px; height: 41px">google</a></li>
- <li><a href="/tag/кино" style="left: 68px; top: 83px; width: 97px; height: 28px">кино</a></li>
- <li><a href="/tag/фото" style="left: 400px; top: 266px; width: 101px; height: 29px">фото</a></li>
- <li><a href="/tag/жизнь" style="left: 554px; top: 266px; width: 125px; height: 27px">жизнь</a></li>
- <li><a href="/tag/еда" style="left: 46px; top: 196px; width: 71px; height: 32px">еда</a></li>
- <li><a href="/tag/музыка" style="left: 61px; top: 111px; width: 139px; height: 27px">музыка</a></li>
- <li><a href="/tag/прекрасное" style="left: 152px; top: 200px; width: 205px; height: 32px">прекрасное</a></li>
- <li><a href="/tag/книги" style="left: 148px; top: 293px; width: 103px; height: 25px">книги</a></li>
- <li><a href="/tag/цитата" style="left: 325px; top: 301px; width: 126px; height: 27px">цитата</a></li> <li><a href="/tag/games" style="left: 117px; top: 142px; width: 30px; height: 104px">games</a></li>
- <li><a href="/tag/ubuntu" style="left: 503px; top: 2px; width: 28px; height: 102px">ubuntu</a></li>
- <li><a href="/tag/котэ" style="left: 534px; top: 27px; width: 76px; height: 28px">котэ</a></li>
- <li><a href="/tag/ВНЕЗАПНО" style="left: 501px; top: 293px; width: 146px; height: 23px">ВНЕЗАПНО</a></li>
- <li><a href="/tag/юмор" style="left: 73px; top: 53px; width: 84px; height: 28px">юмор</a></li>
- <li><a href="/tag/мысли" style="left: 202px; top: 179px; width: 102px; height: 21px">мысли</a></li>
- <li><a href="/tag/pic" style="left: 400px; top: 78px; width: 33px; height: 38px">pic</a></li>
- <li><a href="/tag/политота" style="left: 531px; top: 60px; width: 130px; height: 24px">политота</a></li>
- <li><a href="/tag/WOT" style="left: 159px; top: 63px; width: 48px; height: 20px">WOT</a></li>
- <li><a href="/tag/fail" style="left: 8px; top: 170px; width: 34px; height: 27px">fail</a></li>
- <li><a href="/tag/погода" style="left: 670px; top: 126px; width: 24px; height: 93px">погода</a></li>
- <li><a href="/tag/apple" style="left: 42px; top: 167px; width: 64px; height: 29px">apple</a></li>
- <li><a href="/tag/jabber" style="left: 436px; top: 43px; width: 25px; height: 75px">jabber</a></li>
- <li><a href="/tag/тян" style="left: 532px; top: 94px; width: 47px; height: 21px">тян</a></li>
- <li><a href="/tag/work" style="left: 359px; top: 55px; width: 58px; height: 23px">work</a></li>
- <li><a href="/tag/Python" style="left: 240px; top: 63px; width: 74px; height: 23px">Python</a></li>
- <li><a href="/tag/Видео" style="left: 266px; top: 232px; width: 76px; height: 20px">Видео</a></li>
- <li><a href="/tag/авто" style="left: 359px; top: 30px; width: 58px; height: 24px">авто</a></li>
- <li><a href="/tag/Anime" style="left: 360px; top: 328px; width: 66px; height: 21px">Anime</a></li>
- <li><a href="/tag/игры" style="left: 378px; top: 242px; width: 22px; height: 58px">игры</a></li>
- <li><a href="/tag/вело" style="left: 176px; top: 9px; width: 18px; height: 54px">вело</a></li>
- <li><a href="/tag/web" style="left: 661px; top: 219px; width: 22px; height: 47px">web</a></li>
- <li><a href="/tag/YouTube" style="left: 498px; top: 316px; width: 81px; height: 24px">YouTube</a></li>
- <li><a href="/tag/Вопрос" style="left: 208px; top: 18px; width: 22px; height: 72px">Вопрос</a></li>
- <li><a href="/tag/железо" style="left: 159px; top: 318px; width: 75px; height: 16px">железо</a></li>
- <li><a href="/tag/Microsoft" style="left: 20px; top: 146px; width: 86px; height: 21px">Microsoft</a></li>
- <li><a href="/tag/video" style="left: 616px; top: 101px; width: 51px; height: 19px">video</a></li>
- <li><a href="/tag/Россия" style="left: 32px; top: 242px; width: 68px; height: 16px">Россия</a></li>
- <li><a href="/tag/java" style="left: 409px; top: 226px; width: 39px; height: 22px">java</a></li>
- <li><a href="/tag/новости" style="left: 39px; top: 67px; width: 21px; height: 79px">новости</a></li>
- <li><a href="/tag/интернет" style="left: 100px; top: 233px; width: 17px; height: 85px">интернет</a></li>
- <li><a href="/tag/steam" style="left: 14px; top: 228px; width: 52px; height: 13px">steam</a></li>
- <li><a href="/tag/слова" style="left: 501px; top: 272px; width: 51px; height: 18px">слова</a></li>
- <li><a href="/tag/почта" style="left: 477px; top: 27px; width: 17px; height: 56px">почта</a></li>
- <li><a href="/tag/help" style="left: 123px; top: 281px; width: 21px; height: 35px">help</a></li>
- <li><a href="/tag/skype" style="left: 110px; top: 320px; width: 49px; height: 20px">skype</a></li>
- <li><a href="/tag/debian" style="left: 461px; top: 47px; width: 16px; height: 51px">debian</a></li>
- <li><a href="/tag/win" style="left: 505px; top: 104px; width: 27px; height: 16px">win</a></li>
- <li><a href="/tag/Религия" style="left: 33px; top: 281px; width: 67px; height: 17px">Религия</a></li>
- <li><a href="/tag/soft" style="left: 286px; top: 86px; width: 28px; height: 14px">soft</a></li>
- <li><a href="/tag/Политика" style="left: 144px; top: 281px; width: 75px; height: 12px">Политика</a></li>
- <li><a href="/tag/сны" style="left: 426px; top: 328px; width: 33px; height: 13px">сны</a></li>
- <li><a href="/tag/Питер" style="left: 146px; top: 233px; width: 50px; height: 16px">Питер</a></li>
- <li><a href="/tag/bash" style="left: 451px; top: 311px; width: 38px; height: 16px">bash</a></li>
- <li><a href="/tag/code" style="left: 279px; top: 310px; width: 39px; height: 16px">code</a></li>
- <li><a href="/tag/yandex" style="left: 19px; top: 263px; width: 56px; height: 18px">yandex</a></li>
- <li><a href="/tag/firefox" style="left: 452px; top: 295px; width: 48px; height: 16px">firefox</a></li>
- <li><a href="/tag/hardware" style="left: 230px; top: 40px; width: 67px; height: 18px">hardware</a></li>
- <li><a href="/tag/git" style="left: 78px; top: 258px; width: 20px; height: 19px">git</a></li>
- <li><a href="/tag/dev" style="left: 165px; top: 88px; width: 31px; height: 19px">dev</a></li>
- <li><a href="/tag/mobile" style="left: 421px; top: 24px; width: 15px; height: 47px">mobile</a></li>
- <li><a href="/tag/люди" style="left: 151px; top: 184px; width: 43px; height: 15px">люди</a></li>
- <li><a href="/tag/php" style="left: 149px; top: 24px; width: 27px; height: 18px">php</a></li>
- <li><a href="/tag/haskell" style="left: 271px; top: 293px; width: 48px; height: 16px">haskell</a></li>
- <li><a href="/tag/стихи" style="left: 135px; top: 42px; width: 41px; height: 11px">стихи</a></li>
- <li><a href="/tag/photo" style="left: 639px; top: 219px; width: 20px; height: 39px">photo</a></li>
- <li><a href="/tag/чай" style="left: 448px; top: 220px; width: 27px; height: 14px">чай</a></li>
- <li><a href="/tag/Опрос" style="left: 297px; top: 22px; width: 14px; height: 41px">Опрос</a></li>
- <li><a href="/tag/Chrome" style="left: 311px; top: 25px; width: 48px; height: 17px">Chrome</a></li>
- <li><a href="/tag/life" style="left: 255px; top: 311px; width: 23px; height: 16px">life</a></li>
- <li><a href="/tag/opera" style="left: 226px; top: 232px; width: 38px; height: 14px">opera</a></li>
- <li><a href="/tag/programming" style="left: 234px; top: 327px; width: 81px; height: 14px">programming</a></li>
- <li><a href="/tag/дети" style="left: 15px; top: 197px; width: 31px; height: 13px">дети</a></li>
- <li><a href="/tag/сериалы" style="left: 575px; top: 219px; width: 61px; height: 13px">сериалы</a></li>
- <li><a href="/tag/учеба" style="left: 616px; top: 84px; width: 43px; height: 17px">учеба</a></li>
- </ul>
-
-<div id="bottom1">juick.com &copy; 2008-2018 &nbsp; <a href="/help/ru/contacts" rel="nofollow">Контакты</a> &middot; <a href="/help/" rel="nofollow">Помощь</a></div>
-
-<div id="signup">
- {{ i18n("messages","label.register") }}:
- <div id="facebook"><a href="/_fblogin" rel="nofollow">Facebook</a></div>
- <div id="vk"><a href="/_vklogin" rel="nofollow">ВКонтакте</a></div>
- <div id="tg">
- <script async src="https://telegram.org/js/telegram-widget.js?3"
- data-telegram-login="Juick_bot" data-size="medium" data-radius="0"
- data-auth-url="https://juick.com/_tglogin" data-request-access="write"></script>
- </div>
- </div>
-<div id="signin">
- <a href="#" onclick="$('#signinform').toggle(); $('#nickinput').focus(); return false">
- {{ i18n("messages","question.areRegistered") }}
- </a>
- <div id="signinform"><form action="/login" method="POST">
- <input class="txt" type="text" name="username" placeholder='{{ i18n("messages","label.username") }}' id="nickinput"/>
- <input class="txt" type="password" name="password" placeholder='{{ i18n("messages","label.password") }}'/>
- <input class="submit" type="submit" value="OK"/>
- </form></div>
- </div>
-
-</body>
-</html>
diff --git a/juick-server/src/main/resources/templates/views/login_success.html b/juick-server/src/main/resources/templates/views/login_success.html
deleted file mode 100644
index ee71f12f..00000000
--- a/juick-server/src/main/resources/templates/views/login_success.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>Blank window</title>
-</head>
-<body>
- <script type="text/javascript">
- window.opener.postMessage("{{ hash }}", "*");
- window.close();
- </script>
-</body>
-</html>
diff --git a/juick-server/src/main/resources/templates/views/macros/tags.html b/juick-server/src/main/resources/templates/views/macros/tags.html
deleted file mode 100644
index defed8e6..00000000
--- a/juick-server/src/main/resources/templates/views/macros/tags.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% macro tags(uname="", tagsList) %}
-{% for tag in tagsList %}
-<a href="/{{ uname }}/?tag={{ tag | urlencode }}">{{ tag | raw }}</a>
-{% endfor %}
-{% endmacro %}
-
-{% macro allTags(baseUri, tagsList) %}
-{% for tag in tagsList %}
-<a href="{{ baseUri }}tag/{{ tag | urlencode }}">#{{ tag | raw }}</a>
-{% endfor %}
-{% endmacro %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/partial/footer.html b/juick-server/src/main/resources/templates/views/partial/footer.html
deleted file mode 100644
index 35972254..00000000
--- a/juick-server/src/main/resources/templates/views/partial/footer.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<div id="footer">
- <div id="footer-right"> &middot;
- <a href="/help/contacts" rel="nofollow">{{ i18n("messages","link.contacts") }}</a> &middot;
- <a href="/help/tos" rel="nofollow">{{ i18n("messages","link.tos") }}</a>
- </div>
- <div id="footer-social">
- <a href="https://twitter.com/Juick" rel="nofollow"><i data-icon="ei-sc-twitter" data-size="m"></i></a>
- <a href="https://vk.com/juick" rel="nofollow"><i data-icon="ei-sc-vk" data-size="m"></i></a>
- <a href="https://www.facebook.com/JuickCom" rel="nofollow"><i data-icon="ei-sc-facebook" data-size="m"></i></a>
- </div>
- <div id="footer-left">juick.com &copy; 2008-2018
- {% if links | default ('') is not empty %}
- <br/>{{ i18n("messages","label.sponsors") }}: {{ links | raw }}
- {% endif %}
- </div>
-</div>
diff --git a/juick-server/src/main/resources/templates/views/partial/homecolumn.html b/juick-server/src/main/resources/templates/views/partial/homecolumn.html
deleted file mode 100644
index 01448bca..00000000
--- a/juick-server/src/main/resources/templates/views/partial/homecolumn.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<ul class="toolbar">
- <li>
- <a href="/?show=top" title="Top">
- <i data-icon="ei-heart" data-size="s"></i>Top
- </a>
- </li>
- <li>
- <a href="/?show=all" title="{{ i18n("messages","link.allMessages") }}">
- <i data-icon="ei-search" data-size="s"></i>{{ i18n("messages","link.allMessages") }}
- </a>
- </li>
- <li>
- <a href="/?show=photos" title="{{ i18n("messages","link.withPhotos") }}">
- <i data-icon="ei-camera" data-size="s"></i>{{ i18n("messages","link.withPhotos") }}
- </a>
- </li>
-</ul>
-<div class="tags">
- <h4>{{ i18n("messages","link.trends") }}</h4>
- {% include "views/partial/tags" %}
- {% if showAdv | default(false) %}
- <h4>Наши друзья</h4>
- <a href="https://ru.wix.com/">конструктор сайтов</a>
- {% endif %}
-</div> \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/partial/message.html b/juick-server/src/main/resources/templates/views/partial/message.html
deleted file mode 100644
index 00ca048c..00000000
--- a/juick-server/src/main/resources/templates/views/partial/message.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<article data-mid="{{ msg.mid }}">
- <header class="h">
- <span>
- <a href="/{{ msg.user.name }}/"><span>{{ msg.user.name }}</span></a>
- </span>
- <div class="msg-avatar"><a href="/{{ msg.user.name }}/">
- <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a>
- </div>
- <div class="msg-ts">
- <a href="/{{ msg.user.name }}/{{ msg.mid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
- </time>
- </a>
- </div>
- <div class="msg-tags">
- {{ tags(msg.user.name, msg.tags | tagsList) }}
- </div>
- </header>
- <p>{{ msg | formatMessage }}</p>
- {% if msg.AttachmentType is not empty %}
- <p class="ir"><a href="//i.juick.com/p/{{ msg.mid }}.{{ msg.AttachmentType }}" data-fname="{{ msg.mid }}.{{ msg.AttachmentType }}">
- <img src="//i.juick.com/photos-512/{{ msg.mid }}.{{ msg.AttachmentType }}" alt=""/></a>
- </p>
- {% endif %}
- <nav class="l">
- {% if visitor.uid == msg.user.uid %}
- <a href="/{{ msg.mid }}" class="a-like msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.likes > 0 %}&nbsp;{{ msg.likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
- </a>
- {% elseif visitor.uid > 0 %}
- <a href="/post?body=!+%23{{ msg.mid }}" class="a-like msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.likes > 0 %}&nbsp;{{ msg.likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
- </a>
- {% else %}
- <a href="/login" class="a-login msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.likes > 0 %}&nbsp;{{ msg.likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
- </a>
- {% endif %}
- {% if (not msg.ReadOnly) or (visitor.uid == msg.user.uid) %}
- <a href="/{{ msg.mid }}" class="a-comment msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-comment" data-size="s"></i>
- {% if msg.Replies > 0 %}&nbsp;
- {% if msg.unread %}
- <span class="badge">{{ msg.Replies }}</span>
- {% else %}
- {{ msg.Replies }}
- {% endif %}
- {% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.comment") }}</span>
- </a>
- <a href="#" class="msg-menu msg-button">
- <i data-icon="ei-link" data-size="s"></i>
- <span>&nbsp;{{ i18n("messages","message.share") }}</span>
- </a>
- {% endif %}
- {% if msg.FriendsOnly %}
- <a href="#" class="a-privacy">Открыть доступ</a>
- {% endif %}
- </nav>
-</article> \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/partial/navigation.html b/juick-server/src/main/resources/templates/views/partial/navigation.html
deleted file mode 100644
index 03b6c56d..00000000
--- a/juick-server/src/main/resources/templates/views/partial/navigation.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<header>
- <div id="header_wrapper">
- {% if visitor.uid > 0 %}
- <div id="ctitle">
- <a href="/{{ visitor.name }}">
- <img src="//i.juick.com/a/{{ visitor.uid }}.png" alt=""/>{{ visitor.name }}
- </a>
- </div>
- {% else %}
- <div id="logo"><a href="/{% if visitor.uid > 0 %}?show=my{% endif %}">Juick</a></div>
- {% endif %}
- <div id="search">
- <form action="/">
- <input name="search" class="text"
- placeholder="{{ i18n('messages','label.search') }}" value="{{ search | default('') }}"/>
- </form>
- </div>
- <nav id="global">
- <ul>
- <li><a href="/"><i data-icon="ei-comment" data-size="s"></i>{{ i18n("messages","link.discuss") }}{% if visitor.unreadCount > 0 %}<span class="badge">{{ visitor.unreadCount }}</span>{% endif %}</a></li>
- <li><a href="/?show=all" rel="nofollow"><i data-icon="ei-search" data-size="s"></i>{{ i18n("messages","link.allMessages") }}</a></li>
- {% if visitor.uid > 0 %}
- <li><a id="post" href="/post">
- <i data-icon="ei-pencil" data-size="s"></i>{{ i18n("messages","link.postMessage") }}</a>
- </li>
- {% else %}
- <li>
- <a class="a-login" href="/login" rel="nofollow">
- <i data-icon="ei-user" data-size="s"></i>{{ i18n("messages", "link.Login") }}
- </a>
- </li>
- {% endif %}
- </ul>
- </nav>
- </div>
-</header>
diff --git a/juick-server/src/main/resources/templates/views/partial/settings_tabs.html b/juick-server/src/main/resources/templates/views/partial/settings_tabs.html
deleted file mode 100644
index 4715253e..00000000
--- a/juick-server/src/main/resources/templates/views/partial/settings_tabs.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<div id="pagetabs"><ul>
- <li><a href="/settings">{{ i18n("messages","link.settings.main") }}</a></li>
- <li><a href="/settings?page=password">{{ i18n("messages","link.settings.password") }}</a></li>
- <li><a href="/settings?page=about">{{ i18n("messages","link.settings.about") }}</a></li>
- <li><a href="/logout"><i data-icon="ei-user" data-size="s"></i>{{ i18n("messages","link.logout") }}</a></li>
-</ul></div> \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/partial/tagcolumn.html b/juick-server/src/main/resources/templates/views/partial/tagcolumn.html
deleted file mode 100644
index 3e61d3d3..00000000
--- a/juick-server/src/main/resources/templates/views/partial/tagcolumn.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<div id="ctitle">
- <h2>*{{ tag.name }}</h2>
-</div>
-{% if visitor is not empty and visitor.uid > 0 %}
-<ul class="toolbar">
- {% if isSubscribed %}
- <li>
- <a href="/post?body=U+%2A{{ tag.name }}" title="Подписан">
- <i data-icon="ei-check" data-size="s"></i>Subscribed
- </a>
- </li>
- {% else %}
- <li>
- <a href="/post?body=S+%2A{{ tag.name }}" title="Подписаться">
- <i data-icon="ei-plus" data-size="s"></i>Subscribe
- </a>
- </li>
- {% endif %}
- {% if isInBL %}
- <li>
- <a href="/post?body=BL+%2A{{ tag.name }}" title="Разблокировать">
- <i data-icon="ei-close-o" data-size="s"></i>Unblock
- </a>
- </li>
- {% else %}
- <li>
- <a href="/post?body=BL+%2A{{ tag.name }}" title="Заблокировать">
- <i data-icon="ei-close" data-size="s"></i>Block
- </a>
- </li>
- {% endif %}
-</ul>
-{% endif %}
diff --git a/juick-server/src/main/resources/templates/views/partial/tags.html b/juick-server/src/main/resources/templates/views/partial/tags.html
deleted file mode 100644
index 3235213e..00000000
--- a/juick-server/src/main/resources/templates/views/partial/tags.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{% for tag in tags %}
- <a href="/tag/{{ tag | urlencode }}" title="{{ tag }}">{{ tag | raw }}</a>
-{% endfor %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/partial/usercolumn.html b/juick-server/src/main/resources/templates/views/partial/usercolumn.html
deleted file mode 100644
index 2b1963e3..00000000
--- a/juick-server/src/main/resources/templates/views/partial/usercolumn.html
+++ /dev/null
@@ -1,89 +0,0 @@
-{% if visitor is not empty and visitor.uid > 0 and visitor.uid != user.uid %}
-<div id="ctitle">
- <a href="/{{ user.name }}">
- <img src="//i.juick.com/a/{{ user.uid }}.png" alt=""/>{{ user.name }}
- </a>
-</div>
-<ul class="toolbar">
- {% if isSubscribed %}
- <li>
- <a href="/post?body=U+%40{{ user.name }}" title="Подписан">
- <i data-icon="ei-check" data-size="s"></i>Subscribed
- </a>
- </li>
- {% else %}
- <li>
- <a href="/post?body=S+%40{{ user.name }}" title="Подписаться">
- <i data-icon="ei-plus" data-size="s"></i>Subscribe
- </a>
- </li>
- {% endif %}
- {% if isInBL %}
- <li>
- <a href="/post?body=BL+%40{{ user.name }}" title="Разблокировать">
- <i data-icon="ei-close-o" data-size="s"></i>Unblock
- </a>
- </li>
- {% else %}
- <li>
- <a href="/post?body=BL+%40{{ user.name }}" title="Заблокировать">
- <i data-icon="ei-close" data-size="s"></i>Block
- </a>
- </li>
- {% endif %}
- {% if not isInBLAny %}
- <li>
- <a href="/pm/sent?uname={{ user.name }}" title="Написать приватное сообщение">
- <i data-icon="ei-envelope" data-size="s"></i>PM
- </a>
- </li>
- {% endif %}
-</ul>
-{% else %}
-<hr/>
-{% endif %}
-<ul>
- {% if visitor is not empty and visitor.uid == user.uid %}
- <li><a href="/?show=my"><i data-icon="ei-clock" data-size="s"></i>{{ i18n("messages","link.my") }}</a></li>
- <li><a href="/pm/inbox"><i data-icon="ei-envelope" data-size="s"></i>{{ i18n("messages","link.privateMessages") }}</a></li>
- <li><a href="/?show=discuss"><i data-icon="ei-comment" data-size="s"></i>{{ i18n("messages","link.discuss") }}</a></li>
- {% endif %}
- <li><a href="/{{ user.name }}/?show=recomm" rel="nofollow"><i data-icon="ei-heart" data-size="s"></i>{{ i18n("messages","blog.recommendations") }}</a></li>
- <li><a href="/{{ user.name }}/?show=photos" rel="nofollow"><i data-icon="ei-camera" data-size="s"></i>{{ i18n("messages","blog.photos") }}</a></li>
- {% if visitor is not empty and visitor.uid == user.uid and false %}
- <li><a href="/?show=mycomments" rel="nofollow">{{ i18n("messages","blog.comments") }}</a></li>
- <li><a href="/?show=unanswered" rel="nofollow">Неотвеченные</a></li>
- {% endif %}
- {% if visitor is not empty and visitor.uid == user.uid %}
- <li><a href="/settings" rel="nofollow"><i data-icon="ei-gear" data-size="s"></i>{{ i18n("messages","link.settings") }}</a></li>
- {% endif %}
-</ul>
-<hr/>
-<form action="/{{ user.name }}/">
- <p><input type="text" name="search" class="inp" placeholder="{{ i18n('messages','label.search') }}"/></p>
-</form>
-{% include "views/partial/usertags" %}
-<hr/>
-<div id="ustats">
- <ul>
- <li><a href="/{{ user.name }}/friends">{{ i18n("messages","blog.iread") }}: {{ statsIRead }}</a></li>
- <li><a href="/{{ user.name }}/readers">{{ i18n("messages","blog.readers") }}: {{ statsMyReaders }}</a></li>
- {% if statsMyBL > 0 and visitor.uid == user.uid %}
- <li><a href="/{{ user.name }}/bl">{{ i18n("messages","blog.bl") }}: {{ statsMyBL }}</a></li>
- {% endif %}
- <li>{{ i18n("messages","blog.messages") }}: {{ statsMessages }}</li>
- <li>{{ i18n("messages","blog.comments") }}: {{ statsReplies }}</li>
- </ul>
- {% if iread is not empty %}
- <div class="iread">
- {% for u in iread %}
- <span>
- <a href="/{{ u.name }}/">
- <img src="//i.juick.com/as/{{ u.uid }}.png" alt="{{ u.name }}"/>
- </a>
- </span>
- {% endfor %}
- </div>
- {% endif %}
-
-</div>
diff --git a/juick-server/src/main/resources/templates/views/partial/usertags.html b/juick-server/src/main/resources/templates/views/partial/usertags.html
deleted file mode 100644
index 71d1303e..00000000
--- a/juick-server/src/main/resources/templates/views/partial/usertags.html
+++ /dev/null
@@ -1,3 +0,0 @@
-{% import "views/macros/tags" %}
-{{ tags(user.name, tagStats) }}
-<a href="/{{ user.name }}/tags" rel="nofollow">...</a> \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/pm_inbox.html b/juick-server/src/main/resources/templates/views/pm_inbox.html
deleted file mode 100644
index e82e120e..00000000
--- a/juick-server/src/main/resources/templates/views/pm_inbox.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-{% if not msgs.isEmpty() %}
-<ul id="private-messages">
- {% for msg in msgs %}
- <li class="msg">
- <div class="msg-cont">
- <div class="msg-header">
- @<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>:
- <div class="msg-avatar">
- <a href="/{{ msg.user.name }}/">
- <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/>
- </a>
- </div>
- <div class="msg-ts">{{ msg.timestamp | prettyTime }}</div>
- </div>
-
- <div class="msg-txt">{{ msg | formatMessage }}</div>
- <form class="pmmsg">
- <input type="hidden" name="uname" value="{{ msg.user.name }}"/>
- <div class="msg-comment">
- <div class="ta-wrapper">
- <textarea name="body" rows="1" class="replypm" placeholder="Написать ответ"></textarea>
- </div>
- </div>
- </form>
- </div>
- </li>
- {% endfor %}
-</ul>
-{% endif %}
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% endblock %}
diff --git a/juick-server/src/main/resources/templates/views/pm_sent.html b/juick-server/src/main/resources/templates/views/pm_sent.html
deleted file mode 100644
index dcda64d8..00000000
--- a/juick-server/src/main/resources/templates/views/pm_sent.html
+++ /dev/null
@@ -1,33 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<form class="pmmsg">
- <div class="newpm">
- <div class="newpm-to">To: <input type="text" name="uname" placeholder="username" value="{{ uname }}"/></div>
- <div class="newpm-body"><textarea name="body" rows="2"></textarea></div>
- <div class="newpm-send"><input type="submit" value="OK"/></div>
- </div>
-</form>
-{% if not msgs.isEmpty() %}
-<ul id="private-messages">
- {% for msg in msgs %}
- <li class="msg">
- <div class="msg-cont">
- <div class="msg-header">
- @<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>:
- <div class="msg-avatar">
- <a href="/{{ msg.user.name }}/">
- <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/>
- </a>
- </div>
- <div class="msg-ts">{{ msg.timestamp | prettyTime }}</div>
- </div>
- <div class="msg-txt">{{ msg | formatMessage }}</div>
- </div>
- </li>
- {% endfor %}
-</ul>
-{% endif %}
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% endblock %}
diff --git a/juick-server/src/main/resources/templates/views/post.html b/juick-server/src/main/resources/templates/views/post.html
deleted file mode 100644
index 3753b36c..00000000
--- a/juick-server/src/main/resources/templates/views/post.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "layouts/minimal" %}
-{% import "views/macros/tags" %}
-{% block content %}
-<article>
-<form id="postmsg">
- <p style="text-align: left">
- <b>Фото:</b> <span id="attachmentfile">
- <input style="width: 100%;" type="file" name="attach"/> <i>({{ i18n("messages","postForm.imageFormats") }})</i></span>
- </p>
- <p>
- <textarea name="body" class="newmessage" rows="7" cols="10" placeholder="*weather It's very cold today!">{{ body }}</textarea>
- <br/>
- <input type="submit" class="subm" value=" {{ i18n("messages","postForm.submit") }} "/>
- </p>
-</form>
-</article>
-<p style="text-align: left"><b>Теги:</b></p>
-{{ tags(visitor.name, tags) }}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/post_success.html b/juick-server/src/main/resources/templates/views/post_success.html
deleted file mode 100644
index 2106f3cb..00000000
--- a/juick-server/src/main/resources/templates/views/post_success.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "layouts/minimal" %}
-{% block content %}
-<h1>Сообщение опубликовано</h1>
-<p>Поделитесь своим новым постом в социальных сетях:</p>
-{% if sharetwi | default('') is not empty %}
-<p class="social">
- <a href="https://twitter.com/intent/tweet?text={{ sharetwi }}"
- class="sharenew"><i data-icon="ei-sc-twitter" data-size="m"></i>Отправить в Twitter</a></p>
-{% endif %}
-<p class="social">
- <a href="https://vk.com/share.php?url={{ url | urlencode }}"
- class="sharenew"><i data-icon="ei-sc-vk" data-size="m"></i>Отправить в ВКонтакте</a></p>
-{% if facebook | default('') is not empty %}
-<p class="social">
- <a href="https://www.facebook.com/sharer/sharer.php?u={{ url | urlencode }}"
- class="sharenew"><i data-icon="ei-sc-facebook" data-size="m"></i>Отправить в Facebook</a></p>
-{% endif %}
-<p>Ссылка на сообщение: <a href="{{ url | raw }}">{{ url }}</a></p>
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_about.html b/juick-server/src/main/resources/templates/views/settings_about.html
deleted file mode 100644
index bbf9e772..00000000
--- a/juick-server/src/main/resources/templates/views/settings_about.html
+++ /dev/null
@@ -1,20 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <p>Full name: <input type="text" name="fullname" value="{{ userinfo.fullName }}"/></p>
- <p>Country: <input type="text" name="country" value="{{ userinfo.country }}"/></p>
- <p>URL: <input type="text" name="url" value="{{ userinfo.url }}" size="32"/><br/>
- <small>Please, start with &quot;http://&quot;</small></p>
- <p>About:<br/>
- <input type="text" name="descr" value="{{ userinfo.description }}" style="width: 100%"/><br/>
- <small>Max. 255 symbols</small></p>
- <p>Avatar: <input type="file" name="avatar"/><br/>
- <small>Recommendations: PNG, 96x96, &lt;50Kb. Also, JPG and GIF supported.</small></p>
- <p><input type="hidden" name="page" value="about"/><input type="submit" value=" OK "/></p>
- </form>
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_auth-email.html b/juick-server/src/main/resources/templates/views/settings_auth-email.html
deleted file mode 100644
index e906d704..00000000
--- a/juick-server/src/main/resources/templates/views/settings_auth-email.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <p>{{ result }}</p><p><a href="/settings">Settings</a>.</p>
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_main.html b/juick-server/src/main/resources/templates/views/settings_main.html
deleted file mode 100644
index 65fbc984..00000000
--- a/juick-server/src/main/resources/templates/views/settings_main.html
+++ /dev/null
@@ -1,151 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <h1>Настройки</h1>
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <fieldset>
- <legend>Notification options</legend>
- <p><input type="checkbox" name="jnotify" value="1" {% if notify_options.repliesEnabled %}
- checked="checked" {% endif %}/> Reply notifications (&quot;Message posted&quot;)</p>
- <p><input type="checkbox" name="subscr_notify" value="1" {% if notify_options.subscriptionsEnabled %}
- checked="checked" {% endif %}/> Subscriptions notifications (&quot;@user subscribed...&quot;)</p>
- <p><input type="checkbox" name="recomm" value="1" {% if notify_options.recommendationsEnabled %}
- checked="checked" {% endif %}/> Posts recommendations (&quot;Recommended by @user&quot;)</p>
- <p><input type="hidden" name="page" value="main"/><input type="submit" value=" OK "/></p>
- </fieldset>
- </form>
- <fieldset>
- <legend style="background: url(//telegram.org/favicon.ico?3) no-repeat; padding-left: 58px; line-height: 48px;">
- Telegram</legend>
- {% if telegram_name is not empty %}
- <form action="/settings" method="post">
- <div>Telegram: <b>{{ telegram_name }}</b> &mdash;
- <input type="hidden" name="page" value="telegram-del"/>
- <input type="submit" value=" Disable "/>
- </div>
- </form>
- {% else %}
- <p>To connect Telegram account: send any text message to <a href="https://telegram.me/Juick_bot">@Juick_bot</a>
- </p>
- {% endif %}
- </fieldset>
- {% if jids | length > 0 %}
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <fieldset>
- <legend style="background: url(//static.juick.com/settings/xmpp.png) no-repeat; padding-left: 58px; line-height: 48px;">
- XMPP accounts
- </legend>
- <p>Your accounts:</p>
- <p>
- {% for jid in jids %}
- <label><input type="radio" name="delete" value="xmpp;{{ jid }}">{{ jid }}</label><br/>
- {% endfor %}
- {% for auth in auths %}
- <label><input type="radio" name="delete"
- value="xmpp-unauth;{{ auth.account }}">{{ auth.account }}</label>
- &mdash; <a href="#"
- onclick="alert(\'To confirm, please send &quot;AUTH {{ auth.getAuthCode() }}&quot; (without quotes) from this account to &quot;juick@juick.com&quot;.\'); return false;">Confirm</a><br/>
- {% endfor %}
- </p>
- {% if jids | length > 1 %}
- <p><input type="hidden" name="page" value="jid-del"/><input type="submit" value=" Delete "/></p>
- {% endif %}
- <p>To add new jabber account: send any text message to <a href="xmpp:juick@juick.com?message;body=login">juick@juick.com</a>
- </p>
- </fieldset>
- </form>
- {% endif %}
- <fieldset>
- <legend style="background: url(//static.juick.com/settings/email.png) no-repeat; padding-left: 58px; line-height: 48px;">
- E-mail
- </legend>
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <p>Add account:<br/>
- <input type="text" name="account"/>
- <input type="hidden" name="page" value="email-add"/>
- <input type="submit" value=" Add "/>
- </p>
- </form>
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <p>Your accounts:</p>
- <p>
- {% for email in emails %}
- <label><input type="radio" name="account" value="{{ email }}">{{ email }}</label><br/>
- {% endfor %}
- {% if emails is empty %}
- - </p>
- {% else %}
- </p>
- {% if jids | length > 1 %}
- <p><input type="hidden" name="page" value="email-del"/><input type="submit" value=" Delete "/></p>
- {% endif %}
- {% endif %}
- </form>
- {% if emails is not empty %}
- <!--email_off-->
- <form action="/settings" method="POST" enctype="multipart/form-data">
- <p>You can receive notifications to email:<br/>
- Sent to <select name="account">
- <option value="">Disabled</option>
- {% for email in emails %}
- <option value="{{ email }}" {% if email_active == email %} selected="selected" {% endif %}>
- {{ email }}
- </option>
- {% endfor %}
- </select>
- <input type="hidden" name="page" value="email-subscr"/>
- <input type="submit" value="OK"/></p>
- </form>
- <!--/email_off-->
- {% endif %}
- <p>&nbsp;</p>
- <p>You can post to Juick via e-mail. Send your <span style="text-decoration: underline">plain text</span>
- messages to <span><a href="mailto:juick@juick.com">juick@juick.com</a></span>. You can attach one photo or video file.</p>
- </fieldset>
- <fieldset>
- <legend style="background: url(//static.juick.com/settings/facebook.png) no-repeat; padding-left: 58px; line-height: 48px;">
- Facebook
- </legend>
- {% if fbstatus.connected %}
- {% if fbstatus.crosspostEnabled %}
- <form action="/settings" method="post">
- <div>
- Facebook: <b>Enabled</b> &mdash;
- <input type="hidden" name="page" value="facebook-disable"/>
- <input type="submit" value=" Disable "/>
- </div>
- </form>
- {% else %}
- <form action="/settings" method="post">
- <div>
- Facebook: <b>Disabled</b> &mdash;
- <input type="hidden" name="page" value="facebook-enable"/>
- <input type="submit" value=" Enable "/>
- </div>
- </form>
- {% endif %}
- {% else %}
- <p>Cross-posting to Facebook: <a href="/_fblogin"><img src="//static.juick.com/facebook-connect.png" alt="Connect to Facebook"/></a></p>
- {% endif %}
- </fieldset>
- <fieldset>
- <legend style="background: url(//static.juick.com/settings/twitter.png) no-repeat; padding-left: 58px; line-height: 48px;">
- Twitter</legend>
- {% if twitter_name is not empty %}
- <form action="/settings" method="post">
- <div>Twitter: <b>{{ twitter_name }}</b> &mdash;
- <input type="hidden" name="page" value="twitter-del"/>
- <input type="submit" value=" Disable "/>
- </div>
- </form>
- {% else %}
- <p>Cross-posting to Twitter: <a href="/_twitter"><img src="//static.juick.com/twitter-connect.png"
- alt="Connect to Twitter"/></a></p>
- {% endif %}
- </fieldset>
-
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_password.html b/juick-server/src/main/resources/templates/views/settings_password.html
deleted file mode 100644
index aba0b139..00000000
--- a/juick-server/src/main/resources/templates/views/settings_password.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <fieldset>
- <legend>Changing your password</legend>
- <form action="/settings" method="post">
- <input type="hidden" name="page" value="password"/>
- <p>Change password: <input type="password" name="password" size="8"/> <input type="submit"
- value=" Update "/><br/>
- <i>(max. length - 16 symbols)</i></p>
- </form>
- </fieldset>
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_privacy.html b/juick-server/src/main/resources/templates/views/settings_privacy.html
deleted file mode 100644
index 83b87b93..00000000
--- a/juick-server/src/main/resources/templates/views/settings_privacy.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <p>Privacy</p>
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/settings_result.html b/juick-server/src/main/resources/templates/views/settings_result.html
deleted file mode 100644
index d87a5ea6..00000000
--- a/juick-server/src/main/resources/templates/views/settings_result.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<article>
- <p>{{ result | raw }}</p>
-</article>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/settings_tabs" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/signup.html b/juick-server/src/main/resources/templates/views/signup.html
deleted file mode 100644
index d6eb921f..00000000
--- a/juick-server/src/main/resources/templates/views/signup.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% extends "layouts/default" %}
-{% block content %}
-<h1 class="signup-h1">
- {% if type | slice(0, 1) == 'f' %}
- <img src="//static.juick.com/settings/facebook.png" alt="Facebook"/>
- {% elseif type | slice(0, 1) == 'v' %}
- <img src="//static.juick.com/settings/vk.png" alt="VKontakte"/>
- {% elseif type | slice(0, 1) == 'e' %}
- <img src="//static.juick.com/settings/email.png" alt="Email"/>
- {% elseif type | slice(0, 1) == 'd' %}
- <img src="//telegram.org/favicon.ico?3" alt="Telegram"/>
- {% endif %}
- {{ account | raw }}</h1>
-
-<h2 class="signup-h2">Связать с существующим аккаунтом Juick</h2>
-<form action="/signup" method="post">
- <input type="hidden" name="action" value="link"/>
- <input type="hidden" name="type" value="{{ type }}"/>
- <input type="hidden" name="hash" value="{{ hash }}"/>
- {% if visitor.getUID() > 0 %}
- <input type="submit" value="Связать с этим аккаунтом"/>
- {% else %}
- <p>Имя пользователя: <input type="text" name="username"/></p>
- <p>Пароль: <input type="password" name="password"/></p>
- <p><input type="submit" value=" OK "/></p>
- {% endif %}
-</form>
-
-{% if type != "xmpp" %}
-<hr class="signup-hr"/>
-
-<h2 class="signup-h2">Создать новый аккаунт Juick</h2>
-<form action="/signup" method="post">
- <input type="hidden" name="action" value="new"/>
- <input type="hidden" name="type" value="{{ type }}"/>
- <input type="hidden" name="hash" value="{{ hash }}"/>
- <p>Имя пользователя: <input type="text" name="username" id="username"/><br/><i>(От 2-х до 16-и латинских символов
- и/или цифр, дефис)</i></p>
- <p>Пароль: <input type="password" name="password"/><br/><i>(от 6-и до 32-х символов)</i></p>
- <p><input type="submit" value=" OK "/></p>
-</form>
-{% endif %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/thread.html b/juick-server/src/main/resources/templates/views/thread.html
deleted file mode 100644
index 478258cf..00000000
--- a/juick-server/src/main/resources/templates/views/thread.html
+++ /dev/null
@@ -1,175 +0,0 @@
-{% extends "layouts/default" %}
-{% import "views/macros/tags" %}
-{% block content %}
-<ul id="0">
- <li id="msg-{{ msg.mid }}" class="msg msgthread">
- <div class="msg-cont">
- <div class="msg-header">
- <div class="msg-avatar">
- <a href="/{{ msg.user.name }}/"><img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a>
- </div>
- <span>
- <a href="/{{ msg.user.name }}/"><span>{{ msg.user.name }}</span></a>
- </span>
- <div class="msg-ts">
- <a href="/{{ msg.user.name }}/{{ msg.mid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
- </time>
- </a>
- </div>
- <div class="msg-tags">
- {{ tags(msg.user.name, msg.tags | tagsList) }}
- </div>
- </div>
- <div class="msg-txt">{{ msg | formatMessage }}</div>
- {% if msg.AttachmentType is not empty %}
- <div class="msg-media">
- <a href="//i.juick.com/p/{{ msg.mid }}.{{ msg.AttachmentType }}" data-fname="{{ msg.mid }}.{{ msg.AttachmentType }}">
- <img src="//i.juick.com/photos-512/{{ msg.mid }}.{{ msg.AttachmentType }}" alt=""/>
- </a>
- </div>
- {% endif %}
- <nav class="l">
- {% if visitor.uid == msg.user.uid %}
- <a href="/{{ msg.mid }}" class="a-like msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.Likes > 0 %}&nbsp;{{ msg.Likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
- </a>
- {% elseif visitor.uid > 0 %}
- <a href="/post?body=!+%23{{ msg.mid }}" class="a-like msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.Likes > 0 %}&nbsp;{{ msg.Likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
- </a>
- {% else %}
- <a href="/login" class="a-login msg-button">
- <span class="msg-button-icon">
- <i data-icon="ei-heart" data-size="s"></i>
- {% if msg.Likes > 0 %}&nbsp;{{ msg.Likes }}{% endif %}
- </span>
- <span>&nbsp;{{ i18n("messages","message.recommend") }}</span>
-
- </a>
- {% endif %}
- <a href="#" class="msg-menu msg-button">
- <i data-icon="ei-link" data-size="s"></i>
- <span>&nbsp;{{ i18n("messages","message.share") }}</span>
- </a>
- {% if visitor.uid > 0 %}
- {% if visitor.uid != msg.user.uid %}
- {% if visitorSubscribed %}
- <a href="/post?body=U+%23{{ msg.mid }}" class="msg-button">
- <i data-icon="ei-check" data-size="s"></i>
- <span>&nbsp;{{ i18n("messages","message.subscribed") }}</span>
- </a>
- {% else %}
- <a href="/post?body=S+%23{{ msg.mid }}" class="a-sub msg-button">
- <i data-icon="ei-eye" data-size="s"></i>
- <span>&nbsp;{{ i18n("messages","message.subscribe") }}</span>
- </a>
- {% endif %}
- {% else %}
- <a href="/post?body=D+%23{{ msg.mid }}" class="msg-button">
- <i data-icon="ei-close" data-size="s"></i>
- <span>&nbsp;{{ i18n("messages","message.delete") }}</span>
- </a>
- {% endif %}
- {% endif %}
- {% if msg.FriendsOnly %}
- <a href="#" class="a-privacy">Открыть доступ</a>
- {% endif %}
- </nav>
- {% if msg.VisitorCanComment %}
- <form class="msg-comment-target">
- <input type="hidden" name="mid" value="{{ msg.mid }}"/>
- <div class="msg-comment">
- <div class="ta-wrapper">
- <textarea name="body" rows="1" class="reply" placeholder="{{ i18n("messages","message.writeComment") }}"></textarea>
- </div>
- </div>
- </form>
- {% endif %}
- {% if recomm is not empty %}
- <div class="msg-recomms">{{ i18n("messages","message.recommendedBy") }}
- {% for rec in recomm %}
- <a href="/{{ rec }}/">@{{ rec }}</a>{% if loop.index < (loop.length - 1) %}, {% endif %}
- {% endfor %}
- {% if msg.likes > recomm.size() %}
- &nbsp;{{ i18n("messages","message.recommendedOthers", msg.likes - recomm.size()) }}
- {% endif %}
- </div>
- {% endif %}
- </div>
- </li>
-</ul>
-<div class="title2">
- {% if visitor.uid > 0 %}
- <img src="/api/thread/mark_read/{{ msg.mid }}-{{ msg.rid }}.gif?hash={{visitor.authHash}}" />
- {% endif %}
- <h2>{{ i18n("messages","reply.replies") }} ({{ replies.size() }})</h2>
-</div>
-
-<ul id="replies">
- {% for msg in replies %}
- <li id="{{ msg.rid }}" class="msg">
- <div class="msg-cont">
- <div class="msg-header" data-uri="{{ msg.user.uri }}">
- {% if not msg.user.banned %}
- <a class="a-username" href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>
- <div class="msg-avatar">
- <a class="a-username" href="/{{ msg.user.name }}/">
- <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/>
- </a>
- </div>
- {% else %}
- [удалено]:
- <div class="msg-avatar">
- <img src="//i.juick.com/av-96.png"/>
- </div>
- {% endif %}
- <div class="msg-ts">
- <a href="/{{ msg.mid }}#{{ msg.rid }}">
- <time datetime="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }}Z"
- title="{{ msg.timestamp | timestamp | date('yyyy-MM-dd HH:mm:ss') }} GMT">
- {{ msg.timestamp | prettyTime }}
- </time>
- </a>
- </div>
- </div>
- <div class="msg-txt">{{ msg | formatMessage }}</div>
- {% if msg.AttachmentType is not empty %}
- <div class="msg-media">
- <a href="//i.juick.com/p/{{ msg.mid }}-{{ msg.rid }}.{{ msg.AttachmentType }}" data-fname="{{ msg.mid }}-{{ msg.rid }}.{{ msg.AttachmentType }}">
- <img src="//i.juick.com/photos-512/{{ msg.mid }}-{{ msg.rid }}.{{ msg.AttachmentType }}" alt=""/>
- </a>
- </div>
- {% endif %}
- <div class="msg-links">/{{ msg.rid }}
- {% if msg.replyto > 0 %}
- {{ i18n("messages","reply.inReplyTo") }} <a href="#{{ msg.replyto }}">/{{ msg.replyto }}</a>
- {% endif %}
- {% if msg.VisitorCanComment %}
- &middot; <a href="/post?body=%23{{ msg.mid }}/{{ msg.rid }}%20" class="a-thread-comment">{{ i18n("messages","reply.reply") }}</a>
- </div>
- <div class="msg-comment-target msg-comment-hidden"></div>
- {% elseif visitor.uid == 0 %}
- &middot; <a href="#" class="a-login">{{ i18n("messages","reply.reply") }}</a>
- </div>
- {% else %}
- </div>
- {% endif %}
- </div>
- </li>
- {% endfor %}
-</ul>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% endblock %} \ No newline at end of file
diff --git a/juick-server/src/main/resources/templates/views/users.html b/juick-server/src/main/resources/templates/views/users.html
deleted file mode 100644
index 702ba6b9..00000000
--- a/juick-server/src/main/resources/templates/views/users.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% extends "layouts/default" %}
-{% import "views/macros/tags" %}
-{% block content %}
-<div class="users">
- {% for u in users %}
- <span>
- <a href="/{{ u.name }}/">
- <img src="//i.juick.com/as/{{ u.uid }}.png" alt="{{ u.name }}"/>
- {{ u.name }}
- </a>
- </span>
- {% endfor %}
-</div>
-{% endblock %}
-{% block "column" %}
-{% include "views/partial/usercolumn" %}
-{% endblock %} \ No newline at end of file