diff options
author | Vitaly Takmazov | 2018-11-08 21:38:27 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2018-11-08 21:38:27 +0300 |
commit | 7aaa3f9a29c280f01c677c918932620be45cdbd7 (patch) | |
tree | 39947b2c889afd08f9c73ba54fab91159d2af258 /juick-server | |
parent | 3ea9770d0d43fbe45449ac4531ec4b0a374d98ea (diff) |
Merge everything into single Spring Boot application
Diffstat (limited to 'juick-server')
255 files changed, 0 insertions, 32708 deletions
diff --git a/juick-server/.browserslistrc b/juick-server/.browserslistrc deleted file mode 100644 index 8a747d5e..00000000 --- a/juick-server/.browserslistrc +++ /dev/null @@ -1,2 +0,0 @@ -ie >= 9 -android >= 4.2
\ No newline at end of file diff --git a/juick-server/.eslintrc b/juick-server/.eslintrc deleted file mode 100644 index e1b73925..00000000 --- a/juick-server/.eslintrc +++ /dev/null @@ -1,60 +0,0 @@ -{ - // Extend existing configuration - // from ESlint and eslint-plugin-react defaults. - "extends": [ - "eslint:recommended" - //, "plugin:react/recommended" - ], - // Enable ES6 support. If you want to use custom Babel - // features, you will need to enable a custom parser - // as described in a section below. - "parserOptions": { - "sourceType": "module" - }, - "env": { - "browser": true, - "node": true, - "es6": true - }, - // Enable custom plugin known as eslint-plugin-react - "plugins": [ - // "react" - "only-ascii" - ], - // http://eslint.org/docs/rules/ - "rules": { - "no-console": "off", - "no-underscore-dangle": "warn", - "quotes": ["error", "single"], - - "no-const-assign": "warn", - "no-this-before-super": "warn", - "no-unreachable": "warn", - "no-undef": "warn", - "constructor-super": "warn", - "valid-typeof": "warn", - "no-eq-null": "off", - "no-shadow-restricted-names": "warn", - "no-trailing-spaces": "warn", - "semi": "warn", - "keyword-spacing": "warn", - "block-spacing": "warn", - "arrow-spacing": "warn", - "semi-spacing": "warn", - "brace-style": ["warn", "1tbs", { "allowSingleLine": true }], - "dot-location": ["warn", "property"], - //"indent": ["warn", 2], - "no-tabs": "warn", - "eol-last": "warn", - "comma-style": "warn", - "curly": "warn", - //"no-var": "warn", - "no-shadow": "off", - "no-cond-assign": "off", - "no-sparse-arrays": "off", - "no-unused-vars": "off", - "no-useless-escape": "off", - - "only-ascii/only-ascii": ["warn", { "allowedChars": "✓" }] // "excludePaths": ["i18n.js"] - } -} diff --git a/juick-server/.stylelintrc.json b/juick-server/.stylelintrc.json deleted file mode 100644 index e1c32ef0..00000000 --- a/juick-server/.stylelintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "stylelint-config-standard", - "_rules_documentation" : "https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md", - "rules": { - "at-rule-empty-line-before": null, - "color-hex-case": null, - "color-hex-length": null, - "comment-empty-line-before": null, - "indentation": 4, - "rule-empty-line-before": null, - "selector-pseudo-element-colon-notation": null, - "shorthand-property-no-redundant-values": null, - "no-descending-specificity": null, - "selector-type-no-unknown": null - } -} diff --git a/juick-server/build.gradle b/juick-server/build.gradle deleted file mode 100644 index 69c1f51e..00000000 --- a/juick-server/build.gradle +++ /dev/null @@ -1,125 +0,0 @@ -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'com.moowork.node' -apply plugin: 'io.github.swagger2markup' -apply plugin: 'org.asciidoctor.convert' - -task compileFrontend(type: YarnTask) { - inputs.files(fileTree('node_modules')) - inputs.files(fileTree('src')) - inputs.file('package.json') - inputs.file('webpack.config.js') - outputs.dir('src/main/resources/static') - args = ['run', 'compile'] -} - -ext { - swaggerOutputDir = file("${buildDir}/swagger") - docsOutputDir = file("${buildDir}/docs") -} - -test { - systemProperty 'io.springfox.staticdocs.outputDir', swaggerOutputDir - outputs.dir swaggerOutputDir -} - -convertSwagger2markup { - dependsOn test - swaggerInput "${swaggerOutputDir}/swagger.json" - outputDir swaggerOutputDir - config = [ - 'swagger2markup.markupLanguage' : 'ASCIIDOC', - 'swagger2markup.pathsGroupedBy' : 'TAGS' - ] -} -task asciidocIndex (type: Copy) { - from 'src/docs' - into swaggerOutputDir - include '*.adoc' -} -asciidoctor { - dependsOn convertSwagger2markup - dependsOn asciidocIndex - sourceDir = swaggerOutputDir - sources { - include 'index.adoc', 'overview.adoc', 'definitions.adoc', 'paths.adoc' - } - attributes = [ - doctype: 'book', - toc: 'left', - toclevels: '3', - numbered: '', - sectlinks: '', - sectanchors: '', - hardbreaks: '', - src: swaggerOutputDir, - generated: docsOutputDir - ] - outputDir = docsOutputDir -} - -configurations { - compile.exclude module: 'spring-boot-starter-tomcat' -} - -dependencies { - compile project(':juick-common') - compile 'com.github.ben-manes.caffeine:caffeine:2.6.2' - compile("org.springframework.boot:spring-boot-starter-cache") - compile ('org.springframework.boot:spring-boot-starter-security') - compile ('org.springframework.boot:spring-boot-starter-jdbc') - compile("org.springframework.boot:spring-boot-starter-security") - compile("org.springframework.boot:spring-boot-starter-web") - compile("org.springframework.boot:spring-boot-starter-undertow") - compile("org.springframework.boot:spring-boot-starter-websocket") - compile 'org.springframework.boot:spring-boot-devtools' - - compileOnly 'io.springfox:springfox-core:2.9.2' - - compile 'org.apache.commons:commons-email:1.5' - compile 'com.github.scribejava:scribejava-apis:6.0.0' - compile 'com.github.pengrad:java-telegram-bot-api:4.1.0' - compile 'com.twelvemonkeys.imageio:imageio-jpeg:3.4.1' - compile 'org.imgscalr:imgscalr-lib:4.2' - compile 'org.twitter4j:twitter4j-core:4.0.7' - - compile 'xpp3:xpp3:1.1.4c' - - compile 'rocks.xmpp:xmpp-core-client:0.8.1-SNAPSHOT' - compile 'rocks.xmpp:xmpp-extensions-client:0.8.1-SNAPSHOT' - - compile "javax.inject:javax.inject:1" - - compile 'com.rometools:rome:1.11.1' - compile 'com.rometools:rome-modules:1.11.1' - - compile 'org.flywaydb:flyway-core:5.2.1' - - runtime 'org.mariadb.jdbc:mariadb-java-client:2.3.0' - runtime 'com.h2database:h2:1.4.196' - runtime "commons-fileupload:commons-fileupload:1.3.3" - - compile 'com.github.ooxi:serialized-php-parser:0.5.0' - compile 'io.pebbletemplates:pebble-spring5:3.0.5' - compile 'com.atlassian.commonmark:commonmark:0.11.0' - compile 'com.atlassian.commonmark:commonmark-ext-autolink:0.11.0' - compile 'org.tomitribe:tomitribe-http-signatures:1.1' - - testCompile ("org.springframework.boot:spring-boot-starter-test") - testCompile ('net.sourceforge.htmlunit:htmlunit:2.33') - testCompile ('org.springframework.security:spring-security-test') - - testCompile 'io.springfox:springfox-swagger2:2.9.2' -} - -bootJar { - launchScript() -} - -bootRun { - sourceResources sourceSets.main -} - -bootRun.dependsOn ':generateDebugKey' -compileFrontend.dependsOn 'yarn' -processResources.dependsOn 'compileFrontend' diff --git a/juick-server/package.json b/juick-server/package.json deleted file mode 100644 index 4681bb7c..00000000 --- a/juick-server/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "juick", - "version": "1.0.0", - "private": true, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "compile": "webpack --progress -p" - }, - "repository": { - "type": "git", - "url": "https://github.com/juick/juick.git" - }, - "license": "AGPL-3.0-or-later", - "babel": { - "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "usage" - } - ] - ] - }, - "devDependencies": { - "@babel/core": "^7.1.5", - "@babel/preset-env": "^7.1.5", - "babel-loader": "^8.0.4", - "css-loader": "^1.0.1", - "eslint": "^5.8.0", - "eslint-loader": "^2.1.1", - "eslint-plugin-only-ascii": "0.0.0", - "file-loader": "^2.0.0", - "globby": "^8.0.1", - "mini-css-extract-plugin": "^0.4.4", - "optimize-css-assets-webpack-plugin": "^5.0.1", - "postcss-loader": "^3.0.0", - "script-loader": "^0.7.2", - "style-loader": "^0.23.1", - "stylelint": "^9.7.1", - "stylelint-config-standard": "^18.2.0", - "stylelint-webpack-plugin": "^0.10.5", - "terser-webpack-plugin": "^1.1.0", - "uglify-loader": "^3.0.0", - "url-loader": "^1.1.2", - "webpack": "^4.25.1", - "webpack-cli": "^3.1.2" - }, - "dependencies": { - "@babel/polyfill": "^7.0.0", - "classlist.js": "^1.1.20150312", - "element-closest": "^2.0.2", - "evil-icons": "^1.10.1", - "formdata-polyfill": "^3.0.12", - "url-polyfill": "^1.1.0", - "whatwg-fetch": "^3.0.0" - } -} diff --git a/juick-server/src/docs/index.adoc b/juick-server/src/docs/index.adoc deleted file mode 100644 index 4d492510..00000000 --- a/juick-server/src/docs/index.adoc +++ /dev/null @@ -1,3 +0,0 @@ -include::{src}/overview.adoc[] -include::{src}/paths.adoc[] -include::{src}/definitions.adoc[]
\ No newline at end of file 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(/^(?:>|>)\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: /((?:^(?:>|>)\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 Binary files differdeleted file mode 100644 index 4e0f6d56..00000000 --- a/juick-server/src/main/assets/logo.png +++ /dev/null diff --git a/juick-server/src/main/assets/logo@2x.png b/juick-server/src/main/assets/logo@2x.png Binary files differdeleted file mode 100644 index 6febeaf9..00000000 --- a/juick-server/src/main/assets/logo@2x.png +++ /dev/null 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} · <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 += "&show=" + paramShow; - } - if (paramSearch != null) { - nextpage += "&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 += "&show=" + paramShow; - } - if (paramSearch != null) { - nextpage += "&search=" + URLEncoder.encode(paramSearch, CharEncoding.UTF_8); - } - if (paramTag != null) { - nextpage += "&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 Binary files differdeleted file mode 100644 index 1914264c..00000000 --- a/juick-server/src/main/resources/1x1.png +++ /dev/null diff --git a/juick-server/src/main/resources/Transparent.gif b/juick-server/src/main/resources/Transparent.gif Binary files differdeleted file mode 100644 index f191b280..00000000 --- a/juick-server/src/main/resources/Transparent.gif +++ /dev/null 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 Binary files differdeleted file mode 100644 index a7b0e901..00000000 --- a/juick-server/src/main/resources/juick.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index bc7161e2..00000000 --- a/juick-server/src/main/resources/static/favicon.png +++ /dev/null diff --git a/juick-server/src/main/resources/static/logo.png b/juick-server/src/main/resources/static/logo.png Binary files differdeleted file mode 100644 index 933f6099..00000000 --- a/juick-server/src/main/resources/static/logo.png +++ /dev/null diff --git a/juick-server/src/main/resources/static/tagscloud.png b/juick-server/src/main/resources/static/tagscloud.png Binary files differdeleted file mode 100644 index 3e1bf169..00000000 --- a/juick-server/src/main/resources/static/tagscloud.png +++ /dev/null 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 © 2008-2018 <a href="/help/ru/contacts" rel="nofollow">Контакты</a> · <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"> · - <a href="/help/contacts" rel="nofollow">{{ i18n("messages","link.contacts") }}</a> · - <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 © 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 %} {{ msg.likes }}{% endif %} - </span> - <span> {{ 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 %} {{ msg.likes }}{% endif %} - </span> - <span> {{ 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 %} {{ msg.likes }}{% endif %} - </span> - <span> {{ 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 %} - {% if msg.unread %} - <span class="badge">{{ msg.Replies }}</span> - {% else %} - {{ msg.Replies }} - {% endif %} - {% endif %} - </span> - <span> {{ i18n("messages","message.comment") }}</span> - </a> - <a href="#" class="msg-menu msg-button"> - <i data-icon="ei-link" data-size="s"></i> - <span> {{ 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 "http://"</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, <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 ("Message posted")</p> - <p><input type="checkbox" name="subscr_notify" value="1" {% if notify_options.subscriptionsEnabled %} - checked="checked" {% endif %}/> Subscriptions notifications ("@user subscribed...")</p> - <p><input type="checkbox" name="recomm" value="1" {% if notify_options.recommendationsEnabled %} - checked="checked" {% endif %}/> Posts recommendations ("Recommended by @user")</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> — - <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> - — <a href="#" - onclick="alert(\'To confirm, please send "AUTH {{ auth.getAuthCode() }}" (without quotes) from this account to "juick@juick.com".\'); 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> </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> — - <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> — - <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> — - <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 %} {{ msg.Likes }}{% endif %} - </span> - <span> {{ 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 %} {{ msg.Likes }}{% endif %} - </span> - <span> {{ 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 %} {{ msg.Likes }}{% endif %} - </span> - <span> {{ i18n("messages","message.recommend") }}</span> - - </a> - {% endif %} - <a href="#" class="msg-menu msg-button"> - <i data-icon="ei-link" data-size="s"></i> - <span> {{ 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> {{ 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> {{ 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> {{ 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() %} - {{ 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 %} - · <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 %} - · <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 diff --git a/juick-server/src/test/java/com/juick/server/configuration/SwaggerConfiguration.java b/juick-server/src/test/java/com/juick/server/configuration/SwaggerConfiguration.java deleted file mode 100644 index 7c03f393..00000000 --- a/juick-server/src/test/java/com/juick/server/configuration/SwaggerConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.juick.server.configuration; - -import com.google.common.base.Predicates; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -import java.util.Collections; - -@Configuration -@EnableSwagger2 -public class SwaggerConfiguration { - @Bean - public Docket api() { - return new Docket(DocumentationType.SWAGGER_2) - .host("api.juick.com") - .select() - .apis(Predicates.not(Predicates.or(RequestHandlerSelectors.basePackage("org.springframework.boot"), RequestHandlerSelectors.basePackage("com.juick.server.www")))) - .paths(PathSelectors.any()).build().apiInfo(new ApiInfo("Juick API", "Juick REST API Documentation", - "2.0", "https://juick.com/help/tos", null, - "AGPLv3", "https://www.gnu.org/licenses/agpl-3.0.html", Collections.emptyList())); - } -} diff --git a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java deleted file mode 100644 index 1c643d86..00000000 --- a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java +++ /dev/null @@ -1,1795 +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.tests; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gargoylesoftware.htmlunit.CookieManager; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.css.StyleElement; -import com.gargoylesoftware.htmlunit.html.DomElement; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.jayway.jsonpath.JsonPath; -import com.juick.*; -import com.juick.model.AnonymousUser; -import com.juick.model.CommandResult; -import com.juick.model.PrivateChats; -import com.juick.model.TagStats; -import com.juick.server.*; -import com.juick.server.api.activity.model.Context; -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.Note; -import com.juick.server.api.activity.model.objects.Person; -import com.juick.server.api.webfinger.model.Account; -import com.juick.server.api.xnodeinfo2.model.NodeInfo; -import com.juick.server.util.HttpUtils; -import com.juick.server.util.ImageUtils; -import com.juick.server.xmpp.helpers.XMPPStatus; -import com.juick.server.xmpp.s2s.ConnectionIn; -import com.juick.service.*; -import com.juick.service.component.MessageEvent; -import com.juick.util.DateFormattersHolder; -import com.juick.util.MessageUtils; -import com.mitchellbosecke.pebble.PebbleEngine; -import com.mitchellbosecke.pebble.error.PebbleException; -import com.mitchellbosecke.pebble.template.PebbleTemplate; -import org.apache.commons.codec.CharEncoding; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.IteratorUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.core.io.ClassPathResource; -import org.springframework.http.*; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.util.FileSystemUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.xml.sax.SAXException; -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.session.Extension; -import rocks.xmpp.core.session.XmppSession; -import rocks.xmpp.core.session.XmppSessionConfiguration; -import rocks.xmpp.core.stanza.model.StanzaError; -import rocks.xmpp.core.stanza.model.client.ClientMessage; -import rocks.xmpp.core.stanza.model.errors.Condition; - -import javax.inject.Inject; -import javax.servlet.http.Cookie; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.*; -import java.net.Socket; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.*; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.StreamSupport; - -import static junit.framework.TestCase.assertTrue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -/** - * Created by vitalyster on 25.11.2016. - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -@TestPropertySource(properties = { - "broken_ssl_hosts=localhost,serverstorageisfull.tld", - "ios_app_id=12345678.com.juick.ExampleApp", - "xmppbot_jid=juick@localhost/Juick", - "hostname=localhost", - "componentname=localhost", - "spring.jackson.default-property-inclusion=non_default" -}) -@AutoConfigureMockMvc -public class ServerTests { - - @Inject - private MockMvc mockMvc; - @Inject - private WebClient webClient; - @Inject - private TestRestTemplate restTemplate; - @Inject - private MessagesService messagesService; - @Inject - private UserService userService; - @Inject - private TagService tagService; - @Inject - private ObjectMapper jsonMapper; - @Inject - private XMPPServer server; - @Inject - private CommandsManager commandsManager; - @Inject - private XMPPConnection router; - @Inject - private SubscriptionService subscriptionService; - @Inject - private PrivacyQueriesService privacyQueriesService; - @Inject - private JdbcTemplate jdbcTemplate; - @Inject - private EmailService emailService; - @Inject - private PMQueriesService pmQueriesService; - @Inject - private TelegramService telegramService; - @Inject - private CrosspostService crosspostService; - @Inject - private ImagesService imagesService; - @Inject - private ServerManager serverManager; - @Inject - private KeystoreManager keystoreManager; - @Value("${hostname:localhost}") - private Jid jid; - @Value("${xmppbot_jid:juick@localhost}") - private Jid botJid; - @Value("${upload_tmp_dir:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String tmpDir; - @Value("${img_path:#{systemEnvironment['TEMP'] ?: '/tmp'}}") - private String imgDir; - @Inject - private PebbleEngine pebbleEngine; - @Value("${ios_app_id:}") - private String appId; - @Inject - private SignatureManager signatureManager; - @Inject - private ActivityPubManager activityPubManager; - - private static User ugnich, freefd, juick; - static String ugnichName, ugnichPassword, freefdName, freefdPassword, juickName, juickPassword; - URI emptyUri = URI.create(StringUtils.EMPTY); - - private static boolean isSetUp = false; - - @Before - public void setUp() throws Exception { - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "ps")); - Files.createDirectory(Paths.get(imgDir, "p")); - Files.createDirectory(Paths.get(imgDir, "photos-1024")); - Files.createDirectory(Paths.get(imgDir, "photos-512")); - Files.createDirectory(Paths.get(imgDir, "ps")); - if (!isSetUp) { - ugnichName = "ugnich"; - ugnichPassword = "secret"; - freefdName = "freefd"; - freefdPassword = "MyPassw0rd!"; - juickName = "juick"; - juickPassword = "demo"; - int ugnichId = userService.createUser(ugnichName, ugnichPassword); - ugnich = userService.getUserByUID(ugnichId).orElseThrow(IllegalStateException::new); - int freefdId = userService.createUser(freefdName, freefdPassword); - freefd = userService.getUserByUID(freefdId).orElseThrow(IllegalStateException::new); - int juickId = userService.createUser(juickName, juickPassword); - juick = userService.getUserByUID(juickId).orElseThrow(IllegalStateException::new); - subscriptionService.subscribeUser(freefd, ugnich); - webClient.getOptions().setJavaScriptEnabled(false); - isSetUp = true; - } - } - @After - public void teardown() throws IOException { - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "p")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-1024")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "photos-512")); - FileSystemUtils.deleteRecursively(Paths.get(imgDir, "ps")); - } - @Test - public void getMyFeed() { - int mid0 = messagesService.createMessage(ugnich.getUid(), "test", null, null); - int mid2 = messagesService.createMessage(ugnich.getUid(), "test2", null, null); - List<Integer> freefdFeed = messagesService.getMyFeed(freefd.getUid(), 0, false); - assertThat(freefdFeed.get(0), equalTo(mid2)); - int tonyaid = userService.createUser("Tonya", "secret"); - int mid3 = messagesService.createMessage(tonyaid, "test3", null, null); - messagesService.recommendMessage(mid3, ugnich.getUid()); - assertThat(messagesService.getMyFeed(freefd.getUid(), 0, false).get(0), equalTo(mid2)); - assertThat(messagesService.getMyFeed(freefd.getUid(), 0, true).get(0), equalTo(mid3)); - assertThat(messagesService.getMyFeed(freefd.getUid(), mid2, true).get(0), equalTo(mid0)); - assertThat(messagesService.recommendMessage(mid0, ugnich.getUid()), equalTo(MessagesService.RecommendStatus.Added)); - assertThat(messagesService.getMessage(mid0).getLikes(), equalTo(1)); - assertThat(messagesService.recommendMessage(mid0, ugnich.getUid()), equalTo(MessagesService.RecommendStatus.Deleted)); - assertThat(messagesService.getMessage(mid0).getLikes(), equalTo(0)); - assertThat(messagesService.getAll(ugnich.getUid(), 0).get(0), equalTo(mid3)); - Tag yoTag = tagService.getTag("yoyo", true); - assertThat(tagService.getTag("YOYO", false), equalTo(yoTag)); - int mid = messagesService.createMessage(ugnich.getUid(), "yo", null, Collections.singletonList(yoTag)); - Message msg = messagesService.getMessage(mid); - List<User> subscribers = subscriptionService.getSubscribedUsers(ugnich.getUid(), msg); - - telegramService.createTelegramUser(12345, "freefd"); - String loginhash = jdbcTemplate.queryForObject("SELECT loginhash FROM telegram where tg_id=?", - String.class, 12345); - crosspostService.setTelegramUser(loginhash, freefd.getUid()); - - List<Long> telegramSubscribers = telegramService.getTelegramIdentifiers(subscribers); - assertThat(subscribers.size(), equalTo(1)); - assertThat(subscribers.size(), equalTo(telegramSubscribers.size())); - assertThat(subscribers.get(0).getUid(), equalTo(freefd.getUid())); - tagService.blacklistTag(freefd, yoTag); - List<User> subscribers2 = subscriptionService.getSubscribedUsers(ugnich.getUid(), msg); - assertThat(subscribers2.size(), equalTo(0)); - assertThat(telegramService.getTelegramIdentifiers(subscribers2).size(), equalTo(0)); - tagService.blacklistTag(freefd, yoTag); - assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), msg).size(), equalTo(1)); - subscriptionService.unSubscribeUser(freefd, ugnich); - assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), msg).size(), equalTo(0)); - Message mentionMessage = new Message(); - mentionMessage.setText("@freefd - dick"); - assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mentionMessage).size(), equalTo(1)); - subscriptionService.subscribeUser(freefd, ugnich); - assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mentionMessage).size(), equalTo(1)); - } - @Test - public void pmTests() { - pmQueriesService.createPM(freefd.getUid(), ugnich.getUid(), "hello"); - Message pm = pmQueriesService.getPMMessages(ugnich.getUid(), freefd.getUid()).get(0); - assertThat(pm.getText(), equalTo("hello")); - assertThat(pm.getUser().getUid(), equalTo(freefd.getUid())); - } - - @Test - public void messageTests() { - int user_id = userService.createUser("mmmme", "secret"); - User user = userService.getUserByUID(user_id).orElse(AnonymousUser.INSTANCE); - assertEquals("it should be me", "mmmme", user.getName()); - int mid = messagesService.createMessage(user_id, "yo", null, new ArrayList<>()); - Message msg = messagesService.getMessage(mid); - assertEquals("yo", msg.getText()); - User me = msg.getUser(); - assertEquals("mmmme", me.getName()); - assertEquals("mmmme", messagesService.getMessageAuthor(mid).getName()); - int tagID = tagService.createTag("weather"); - Tag tag = tagService.getTag(tagID); - List<Tag> tagList = new ArrayList<>(); - tagList.add(tag); - int mid2 = messagesService.createMessage(user_id, "yo2", null, tagList); - Message msg2 = messagesService.getMessage(mid2); - assertEquals(1, msg2.getTags().size()); - assertEquals("we already have ugnich", -1, userService.createUser("ugnich", "x")); - int ugnich_id = userService.createUser("hugnich", "x"); - User ugnich = userService.getUserByUID(ugnich_id).orElse(AnonymousUser.INSTANCE); - int rid = messagesService.createReply(msg2.getMid(), 0, ugnich, "bla-bla", null); - assertEquals(1, rid); - assertThat(msg2.getTo(), equalTo(AnonymousUser.INSTANCE)); - Message reply = messagesService.getReply(msg2.getMid(), rid); - assertThat(reply.getTo().getName(), equalTo(user.getName())); - List<Message> replies = messagesService.getReplies(user, msg2.getMid()); - assertThat(replies.size(), equalTo(1)); - assertThat(replies.get(0), equalTo(reply)); - int ridToReply = messagesService.createReply(msg2.getMid(), 1, ugnich, "blax2", null); - Message reply2 = messagesService.getReply(msg2.getMid(), ridToReply); - assertThat(reply.getTo().getName(), equalTo(user.getName())); - List<Message> replies2 = messagesService.getReplies(user, msg2.getMid()); - assertThat(replies2.size(), equalTo(2)); - assertThat(replies2.get(1), equalTo(reply2)); - - Message msg3 = messagesService.getMessage(mid2); - - assertEquals(2, msg3.getReplies()); - assertEquals("weather", msg3.getTags().get(0).getName()); - assertEquals(ugnich.getUid(), userService.checkPassword(ugnich.getName(), "x")); - assertEquals(-1, userService.checkPassword(ugnich.getName(), "xy")); - - subscriptionService.subscribeMessage(msg, user); - subscriptionService.subscribeMessage(msg, ugnich); - int reply_id = messagesService.createReply(msg.getMid(), 0, ugnich, "comment", null); - assertEquals(1, subscriptionService.getUsersSubscribedToComments(msg, - messagesService.getReply(msg.getMid(), reply_id)).size()); - assertThat(messagesService.getDiscussions(ugnich.getUid(), 0L).get(0), - equalTo(msg.getMid())); - messagesService.deleteMessage(user_id, mid); - messagesService.deleteMessage(user_id, mid2); - String htmlTagName = ">_<"; - Tag htmlTag = tagService.getTag(htmlTagName, true); - TagStats htmlTagStats = new TagStats(); - htmlTagStats.setTag(htmlTag); - String dbTagName = jdbcTemplate.queryForObject("select name from tags where name=?", String.class, htmlTagName); - assertEquals("db tags should not be escaped", dbTagName, htmlTag.getName()); - int mid4 = messagesService.createMessage(user_id, "yoyoyo", null, null); - Message msg4 = messagesService.getMessage(mid4); - assertEquals("tags string should be empty", StringUtils.EMPTY, MessageUtils.getTagsString(msg4)); - messagesService.deleteMessage(user_id, mid4); - } - public ExpectedException exception = ExpectedException.none(); - - @Test - public void likeTypeStatsTests(){ - int user_id = userService.createUser("dsdss", "secret"); - final int freefdId = freefd.getUid(); - int mid = messagesService.createMessage(user_id, "yo", null, new ArrayList<>()); - messagesService.likeMessage(mid, freefdId , 2); - messagesService.likeMessage(mid, freefdId,2); - messagesService.likeMessage(mid, freefdId,3); - messagesService.likeMessage(mid, freefdId,1); - - Message msg4 = messagesService.getMessage(mid); - assertThat(msg4.getLikes(), equalTo(1)); - - Assert.assertEquals(2, msg4.getReactions().stream().filter(r -> r.getId() == 2) - .findFirst().orElseThrow(IllegalStateException::new).getCount()); - Assert.assertEquals(1,msg4.getReactions().stream().filter(r -> r.getId() == 3) - .findFirst().orElseThrow(IllegalStateException::new).getCount()); - } - @Test - public void lastJidShouldNotBeDeleted() { - int ugnich_id = userService.createUser("hugnich2", "x"); - jdbcTemplate.update("INSERT INTO jids(user_id,jid,active) VALUES(?,?,?)", ugnich_id, "firstjid@localhost", 1); - jdbcTemplate.update("INSERT INTO jids(user_id,jid,active) VALUES(?,?,?)", ugnich_id, "secondjid@localhost", 1); - assertThat(userService.deleteJID(ugnich_id, "secondjid@localhost"), equalTo(true)); - assertThat(userService.deleteJID(ugnich_id, "firstjid@localhost"), equalTo(false)); - } - @Test - public void lastEmailShouldNotBeDeleted() { - int ugnich_id = userService.createUser("hugnich3", "x"); - jdbcTemplate.update("INSERT INTO emails(user_id,email) VALUES(?,?)", ugnich_id, "first@localhost"); - jdbcTemplate.update("INSERT INTO emails(user_id,email) VALUES(?,?)", ugnich_id, "second@localhost"); - assertThat(emailService.deleteEmail(ugnich_id, "second@localhost"), equalTo(true)); - assertThat(emailService.deleteEmail(ugnich_id, "first@localhost"), equalTo(false)); - } - @Test - public void messageUpdatedTimeShouldMatchLastReplyTime() throws InterruptedException { - int ugnich_id = userService.createUser("hugnich4", "x"); - int mid = messagesService.createMessage(ugnich_id, "yo", null, null); - Instant ts = jdbcTemplate.queryForObject("SELECT updated FROM messages WHERE message_id=?", - Timestamp.class, mid).toInstant(); - Thread.sleep(1000); - int rid = messagesService.createReply(mid, 0, ugnich, "people", null); - Instant rts = jdbcTemplate.queryForObject("SELECT updated FROM messages WHERE message_id=?", - Timestamp.class, mid).toInstant(); - assertThat(rts, greaterThan(ts)); - Message msg = messagesService.getReply(mid, rid); - assertThat(rts, equalTo(msg.getTimestamp())); - messagesService.deleteMessage(ugnich_id, mid); - } - - @Test - public void testAllUnAuthorized() throws Exception { - mockMvc.perform(get("/api/")) - .andExpect(status().isMovedPermanently()); - - mockMvc.perform(get("/api/auth")) - .andExpect(status().isUnauthorized()); - - mockMvc.perform(get("/api/home")) - .andExpect(status().isUnauthorized()); - - mockMvc.perform(get("/api/messages/recommended")) - .andExpect(status().isUnauthorized()); - - mockMvc.perform(get("/api/messages/set_privacy")) - .andExpect(status().isUnauthorized()); - } - - @Test - public void homeTestWithMessages() throws Exception { - String msgText = "Привет, я - Угнич"; - CommandResult result = commandsManager.processCommand(ugnich, msgText, URI.create("http://static.juick.com/settings/facebook.png")); - int mid = result.getNewMessage().get().getMid(); - Message msg = messagesService.getMessage(mid); - tagService.createTag("тест"); - mockMvc.perform( - get("/api/home") - .with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) - .andExpect(jsonPath("$[0].mid", is(msg.getMid()))) - .andExpect(jsonPath("$[0].timestamp", - is(DateFormattersHolder.getMessageFormatterInstance().format(msg.getTimestamp())))) - .andExpect(jsonPath("$[0].body", is(msg.getText()))) - .andExpect(jsonPath("$[0].attachment.url", - is(String.format("https://i.juick.com/p/%d.png", msg.getMid())))) - .andExpect(jsonPath("$[0].attachment.small.url", - is(String.format("https://i.juick.com/photos-512/%d.png", msg.getMid())))) - .andExpect(jsonPath("$[0].user.avatar").doesNotExist()); - } - - @Test - public void homeTestWithMessagesAndRememberMe() throws Exception { - String ugnichHash = userService.getHashByUID(ugnich.getUid()); - mockMvc.perform( - get("/api/home") - .with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()) - .andReturn(); - - mockMvc.perform(get("/api/home") - .param("hash", ugnichHash)) - .andExpect(status().isOk()); - } - - @Test - public void homeTestWithMessagesAndSimpleCors() throws Exception { - mockMvc.perform( - get("/api/home") - .with(httpBasic(ugnichName, ugnichPassword)) - .header("Origin", "http://api.example.net")) - .andExpect(status().isOk()) - .andExpect(header().string("Access-Control-Allow-Origin", "*")); - } - - @Test - public void homeTestWithPreflightCors() throws Exception { - mockMvc.perform( - options("/api/home") - .with(httpBasic(ugnichName, ugnichPassword)) - .header("Origin", "http://api.example.net") - .header("Access-Control-Request-Method", "POST") - .header("Access-Control-Request-Headers", "X-PINGOTHER, Content-Type")) - .andExpect(status().isOk()) - .andExpect(header().string("Access-Control-Allow-Origin", "*")) - .andExpect(header().string("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE")) - .andExpect(header().string("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type")); - } - - @Test - public void anonymousApis() throws Exception { - - - mockMvc.perform(get("/api/messages")) - .andExpect(status().isOk()); - - mockMvc.perform(get("/api/users") - .param("uname", "ugnich") - .param("uname", "freefd")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) - .andExpect(jsonPath("$", hasSize(2))); - } - - @Test - public void messagesUrlTest() throws Exception { - int user_id = userService.createUser("dsds4345", "secret"); - - String freefdHash = userService.getHashByUID(freefd.getUid()); - System.out.println("user_id"+ user_id); - String userIdHash = userService.getHashByUID(user_id); - final int freefdId = freefd.getUid(); - int mid = messagesService.createMessage(user_id, "yo", null, new ArrayList<>()); - messagesService.likeMessage(mid, freefdId, 2 ); - messagesService.likeMessage(mid, freefdId, 2 ); - messagesService.likeMessage(mid, freefdId, 3 ); - - mockMvc.perform(get("/api/messages?"+ "hash=" + userIdHash)) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) - .andExpect((jsonPath("$[0].reactions[?(@.id == 3)].count", - is(Collections.singletonList(1))))) - .andExpect((jsonPath("$[0].reactions[?(@.id == 2)].count", - is(Collections.singletonList(2))))); - - mockMvc.perform(get("/api/reactions?hash=" + userIdHash)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) - .andExpect(jsonPath("$.length()", is(7))); - } - - @Test - public void tags() throws Exception { - Tag weather = tagService.getTag("weather", true); - Tag yo = tagService.getTag("yo", true); - messagesService.createMessage(ugnich.getUid(), "text", null, Arrays.asList(yo, weather)); - messagesService.createMessage(freefd.getUid(), "text2", null, Collections.singletonList(yo)); - MvcResult result = mockMvc.perform(get("/api/tags")) - .andExpect(status().isOk()) - .andReturn(); - List<TagStats> tagsFromApi = jsonMapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<List<TagStats>>(){}); - TagStats yoStats = tagsFromApi.stream().filter(t -> t.getTag().getName().equals("yo")).findFirst().get(); - assertThat(yoStats.getUsageCount(), is(2)); - MvcResult result2 = mockMvc.perform(get("/api/tags") - .param("user_id", String.valueOf(ugnich.getUid()))) - .andExpect(status().isOk()) - .andReturn(); - List<TagStats> ugnichTagsFromApi = jsonMapper.readValue(result2.getResponse().getContentAsString(), - new TypeReference<List<TagStats>>(){}); - TagStats yoUgnichStats = ugnichTagsFromApi.stream().filter(t -> t.getTag().getName().equals("yo")).findFirst().get(); - assertThat(yoUgnichStats.getUsageCount(), is(1)); - } - - @Test - public void postWithReferer() throws Exception { - mockMvc.perform(post("/api/post") - .param("body", "yo") - .with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()); - } - @Test - public void threadWithEphemeralNumberShouldReturn404() throws Exception { - mockMvc.perform(get("/api/thread").param("mid", "999999999") - .with(httpBasic(ugnichName, ugnichPassword))).andExpect(status().is4xxClientError()); - } - @Test - public void performRequestsWithIssuedToken() throws Exception { - String ugnichHash = userService.getHashByUID(ugnich.getUid()); - mockMvc.perform(get("/api/home")).andExpect(status().isUnauthorized()); - mockMvc.perform(get("/api/auth")) - .andExpect(status().isUnauthorized()); - mockMvc.perform(get("/api/auth").with(httpBasic(ugnichName, "wrongpassword"))) - .andExpect(status().isUnauthorized()); - MvcResult result = mockMvc.perform(get("/api/auth").with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()) - .andReturn(); - String authHash = result.getResponse().getContentAsString(); - assertThat(authHash, equalTo(ugnichHash)); - mockMvc.perform(get("/api/home").param("hash", ugnichHash)).andExpect(status().isOk()); - } - @Test - public void registerForNotificationsTests() throws Exception { - String token = "123456"; - ExternalToken registration = new ExternalToken(null, "apns", token, null); - mockMvc.perform(put("/api/notifications").with(httpBasic(ugnichName, ugnichPassword)) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(jsonMapper.writeValueAsBytes(Collections.singletonList(registration)))) - .andExpect(status().isOk()); - MvcResult result = mockMvc.perform(get("/api/notifications") - .param("uid", String.valueOf(ugnich.getUid())) - .with(httpBasic(juickName, juickPassword))) - .andExpect(status().isOk()) - .andReturn(); - List<User> user = jsonMapper.readValue(result.getResponse().getContentAsString(), - new TypeReference<List<User>>() { - }); - assertThat(user.get(0).getTokens().get(0).getToken(), equalTo(token)); - } - @Test - public void tg2juickLinks() { - UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://juick.com/m/123456#23").build(); - assertThat(uriComponents.getPath().substring(3), is("123456")); - assertThat(uriComponents.getFragment(), is("23")); - } - @Test - public void notificationsTokensTest() throws Exception { - List<ExternalToken> tokens = Collections.singletonList(new ExternalToken(null, "gcm", "123456", null)); - mockMvc.perform(delete("/api/notifications").with(httpBasic(ugnichName, ugnichPassword)) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(jsonMapper.writeValueAsBytes(tokens))).andExpect(status().isForbidden()); - mockMvc.perform(delete("/api/notifications").with(httpBasic(juickName, juickPassword)) - .contentType(MediaType.APPLICATION_JSON_UTF8) - .content(jsonMapper.writeValueAsBytes(tokens))).andExpect(status().isOk()); - } - @Test - public void notificationsSettingsAllowedOnlyForServiceUser() throws Exception { - CommandResult result = commandsManager.processCommand(ugnich, "yo", emptyUri); - String stringValueOfMid = String.valueOf(result.getNewMessage().get().getMid()); - mockMvc.perform(get("/api/notifications").with(httpBasic(juickName, juickPassword)) - .param("mid", stringValueOfMid).param("uid", String.valueOf(ugnich.getUid()))).andExpect(status().isOk()); - mockMvc.perform(get("/api/notifications") - .param("mid", stringValueOfMid).param("uid", String.valueOf(ugnich.getUid()))).andExpect(status().isUnauthorized()); - } - @Test - public void topTest() { - int topmid = messagesService.createMessage(ugnich.getUid(), "top message", null, null); - IntStream.rangeClosed(6, 12).forEach(i -> { - User next = new User(); - next.setUid(i); - messagesService.createReply(topmid, 0, next, "yo", null); - }); - - List<Integer> topCandidates = messagesService.getPopularCandidates(); - assertThat(topCandidates.size(), is(1)); - assertThat(topCandidates.get(0), is(topmid)); - Tag juickTag = tagService.getTag("juick", false); - assertThat(juickTag.TID, is(2)); - tagService.updateTags(topmid, Collections.singletonList(juickTag)); - assertThat(messagesService.getPopularCandidates().isEmpty(), is(true)); - tagService.updateTags(topmid, Collections.singletonList(juickTag)); - assertThat(messagesService.getPopularCandidates().isEmpty(), is(false)); - jdbcTemplate.update("INSERT INTO tags(tag_id, name) VALUES(805, 'NSFW')"); - Tag nsfw = tagService.getTag("NSFW", false); - assertThat(nsfw.TID, equalTo(805)); - tagService.updateTags(topmid, Collections.singletonList(nsfw)); - assertThat(messagesService.getPopularCandidates().isEmpty(), is(true)); - } - @Test - public void inReplyToScannerTest() { - String header = "<123456.56@juick.com>"; - Scanner headerScanner = new Scanner(header).useDelimiter(EmailManager.MSGID_PATTERN); - int mid = Integer.parseInt(headerScanner.next()); - int rid = Integer.parseInt(headerScanner.next()); - assertThat(mid, equalTo(123456)); - assertThat(rid, equalTo(56)); - } - @Test - public void lastMessagesTest() throws Exception { - mockMvc.perform( - get("/rss/")) - .andExpect(status().isOk()) - .andExpect(content().contentType("application/rss+xml;charset=UTF-8")) - .andExpect(xpath("/rss/channel/description").string("The latest messages at Juick")); - } - @Test - public void statusPageIsUp() throws Exception { - mockMvc.perform(get("/api/status").with(httpBasic(ugnichName, ugnichPassword))).andExpect(status().isOk()); - assertThat(server.getJid(), equalTo(jid)); - } - @Test - public void botIsUpAndProcessingResourceConstraints() throws Exception { - jdbcTemplate.execute("DELETE FROM users WHERE nick='renha'"); - int renhaId = userService.createUser("renha", "umnnbt"); - Jid from = Jid.of("renha@serverstorageisfull.tld"); - jdbcTemplate.update("INSERT INTO jids(user_id,jid,active) VALUES(?,?,?)", - renhaId, from.toEscapedString(), 1); - rocks.xmpp.core.stanza.model.Message xmppMessage = new rocks.xmpp.core.stanza.model.Message(); - xmppMessage.setType(rocks.xmpp.core.stanza.model.Message.Type.ERROR); - xmppMessage.setFrom(from); - xmppMessage.setTo(botJid); - StanzaError err = new StanzaError(StanzaError.Type.CANCEL, Condition.RESOURCE_CONSTRAINT); - xmppMessage.setError(err); - Function<Integer, Boolean> isActive = f -> jdbcTemplate.queryForObject("SELECT active FROM jids WHERE user_id=?", Integer.class, f) == 1; - assertThat(isActive.apply(renhaId), equalTo(true)); - ClientMessage result = router.incomingMessage(xmppMessage); - assertNull(result); - assertThat(isActive.apply(renhaId), equalTo(false)); - xmppMessage.setError(null); - xmppMessage.setType(rocks.xmpp.core.stanza.model.Message.Type.CHAT); - xmppMessage.setBody("On"); - result = router.incomingMessage(xmppMessage); - assertThat(result.getBody(), equalTo("XMPP notifications are activated")); - assertTrue(isActive.apply(renhaId)); - xmppMessage.setBody("*test test"); - result = router.incomingMessage(xmppMessage); - assertThat(result.getBody(), startsWith("New message posted")); - xmppMessage.setFrom(from); - xmppMessage.setBody("PING"); - result = router.incomingMessage(xmppMessage); - assertThat(result.getBody(), equalTo("PONG")); - int secretlySadId = userService.createUser("secretlysad", "bbk"); - xmppMessage.setTo(botJid.withLocal("secretlysad")); - xmppMessage.setBody("What's up?"); - result = router.incomingMessage(xmppMessage); - assertThat(result.getBody(), startsWith("Private message sent")); - String xml = "<message xmlns=\"jabber:server\" from=\"" + botJid + "\" to=\"renha@serverstorageisfull.tld\" type=\"chat\"><body>@yo:\n" + - "343432434\n" + - "\n" + - "#2 http://juick.com/2</body><thread>juick-2</thread><juick xmlns=\"http://juick.com/message\" mid=\"2\" privacy=\"1\" quote=\"\" replyto=\"0\" rid=\"0\" ts=\"2018-04-10 06:58:23\"><body>343432434</body><updated></updated><user xmlns=\"http://juick.com/user\" uname=\"yo\" uid=\"2\"></user></juick><nick xmlns=\"http://jabber.org/protocol/nick\">@yo</nick></message>"; - result = router.incomingMessage((rocks.xmpp.core.stanza.model.Message)server.parse(xml)); - String active = "<message xmlns=\"jabber:server\" from=\"renha@serverstorageisfull.tld/work\" to=\"" - + botJid.asBareJid().toEscapedString() + "\" type=\"chat\" id=\"purple553384c6\"><active xmlns=\"http://jabber.org/protocol/chatstates\"></active></message>"; - result = router.incomingMessage((rocks.xmpp.core.stanza.model.Message)server.parse(active)); - xmppMessage.setFrom(botJid); - // TODO: assert events - } - @Test - public void botCommandsTests() throws Exception { - assertThat(commandsManager.processCommand(AnonymousUser.INSTANCE, "PING", emptyUri).getText(), is("PONG")); - // subscription commands have two lines, others have 1 - assertThat(commandsManager.processCommand(AnonymousUser.INSTANCE, "help", emptyUri).getText().split("\n").length, is(32)); - } - - @Test - public void protocolTests() throws Exception { - int uid = userService.createUser("me", "secret"); - User user = userService.getUserByUID(uid).orElse(AnonymousUser.INSTANCE); - Tag yo = tagService.getTag("yo", true); - Message msg = commandsManager.processCommand(user, "*yo yoyo", URI.create("http://static.juick.com/settings/facebook.png")).getNewMessage().get(); - assertThat(msg.getAttachmentType(), is("png")); - Message msgreply = commandsManager.processCommand(user, "#" + msg.getMid() + " yyy", HttpUtils.downloadImage(URI.create("http://static.juick.com/settings/xmpp.png").toURL(), tmpDir)).getNewMessage().get(); - assertThat(msgreply.getAttachmentType(), equalTo("png")); - assertEquals("text should match", "yoyo", - messagesService.getMessage(msg.getMid()).getText()); - assertEquals("tag should match", "yo", - tagService.getMessageTags(msg.getMid()).get(0).getTag().getName()); - CommandResult yoyoMsg = commandsManager.processCommand(user, "*yo", URI.create("http://static.juick.com/settings/facebook.png")); - assertTrue(yoyoMsg.getNewMessage().isPresent()); - assertThat(yoyoMsg.getNewMessage().get().getTags().get(0), is(yo)); - Message msg2 = yoyoMsg.getNewMessage().get(); - int mid = msg2.getMid(); - Timestamp last = jdbcTemplate.queryForObject("SELECT lastmessage FROM users WHERE id=?", Timestamp.class, user.getUid()); - assertThat(last.toInstant(), equalTo(yoyoMsg.getNewMessage().get().getTimestamp())); - assertEquals("should be message", true, - commandsManager.processCommand(user, String.format("#%d", mid), emptyUri).getText().startsWith("@me")); - int readerUid = userService.createUser("dummyReader", "dummySecret"); - User readerUser = userService.getUserByUID(readerUid).orElse(AnonymousUser.INSTANCE); - assertThat(commandsManager.processCommand(readerUser, "s", emptyUri).getText().startsWith("You are subscribed to"), is(true)); - assertThat(commandsManager.processCommand(readerUser, "S", emptyUri).getText().startsWith("You are subscribed to"), is(true)); - assertEquals("should be subscribed", "Subscribed", - commandsManager.processCommand(readerUser, "S #" + mid, emptyUri).getText()); - assertEquals("should be favorited", "Message is added to your recommendations", - commandsManager.processCommand(readerUser, "! #" + mid, emptyUri).getText()); - int rid = messagesService.createReply(mid, 0, user, "comment", null); - assertEquals("number of subscribed users should match", 1, - subscriptionService.getUsersSubscribedToComments( - messagesService.getMessage(mid), - messagesService.getReply(mid, rid)).size()); - privacyQueriesService.blacklistUser(user, readerUser); - assertEquals("number of subscribed users should match", 0, - subscriptionService.getUsersSubscribedToComments( - messagesService.getMessage(mid), - messagesService.getReply(mid, rid)).size()); - assertEquals("number of subscribed users should match", 1, - subscriptionService.getUsersSubscribedToComments( - messagesService.getMessage(mid), - messagesService.getReply(mid, rid), true).size()); - assertEquals("should be subscribed", "Subscribed to @" + user.getName(), - commandsManager.processCommand(readerUser, "S @" + user.getName(), emptyUri) - .getText()); - List<User> friends = userService.getUserFriends(readerUid); - assertEquals("number of friend users should match", 2, - friends.size()); - assertEquals("number of reader users should match", 1, - userService.getUserReaders(uid).size()); - String expectedSecondReply = "Reply posted.\n#" + mid + "/2 " - + "https://juick.com/m/" + mid + "#2"; - String expectedThirdReply = "Reply posted.\n#" + mid + "/3 " - + "https://juick.com/m/" + mid + "#3"; - assertEquals("should be second reply", expectedSecondReply, - commandsManager.processCommand(user, "#" + mid + " yoyo", URI.create("http://static.juick.com/settings/facebook.png")).getText()); - assertEquals("should be third reply", expectedThirdReply, - commandsManager.processCommand(user, " \t\n #" + mid + "/2 ", - URI.create("http://static.juick.com/settings/facebook.png")).getText()); - Message reply = messagesService.getReplies(user, mid).stream().filter(m -> m.getRid() == 3).findFirst() - .orElse(new Message()); - Timestamp lastreply = jdbcTemplate.queryForObject("SELECT lastmessage FROM users WHERE id=?", Timestamp.class, user.getUid()); - assertThat(lastreply.toInstant(), equalTo(reply.getTimestamp())); - assertEquals("should be reply to second comment", 2, reply.getReplyto()); - assertEquals("tags should NOT be updated", "It is not your message", - commandsManager.processCommand(readerUser, "#" + mid + " *yo *there", emptyUri) - .getText()); - assertEquals("tags should be updated", "Tags are updated", - commandsManager.processCommand(user, "#" + mid + " *there", emptyUri).getText()); - assertEquals("number of tags should match", 2, - tagService.getMessageTags(mid).size()); - assertThat(messagesService.getMessage(mid).getTags().size(), is(2)); - assertEquals("should be blacklisted", "Tag added to your blacklist", - commandsManager.processCommand(readerUser, "BL *there", emptyUri).getText()); - assertEquals("number of subscribed users should match", 0, - subscriptionService.getSubscribedUsers(uid, msg2).size()); - assertEquals("tags should be updated", "Tags are updated", - commandsManager.processCommand(user, "#" + mid + " *there", emptyUri).getText()); - assertEquals("number of tags should match", 1, - tagService.getMessageTags(mid).size()); - int taggerUid = userService.createUser("dummyTagger", "dummySecret"); - User taggerUser = userService.getUserByUID(taggerUid).orElse(AnonymousUser.INSTANCE); - assertEquals("should be subscribed", "Subscribed", - commandsManager.processCommand(taggerUser, "S *yo", emptyUri).getText()); - assertEquals("number of subscribed users should match", 2, - subscriptionService.getSubscribedUsers(uid, msg2).size()); - assertEquals("should be unsubscribed", "Unsubscribed from yo", - commandsManager.processCommand(taggerUser, "U *yo", emptyUri).getText()); - assertEquals("number of subscribed users should match", 1, - subscriptionService.getSubscribedUsers(uid, msg2).size()); - assertEquals("number of readers should match", 1, - userService.getUserReaders(uid).size()); - String readerFeed = commandsManager.processCommand(readerUser, "#", emptyUri).getText(); - assertTrue("description should match", readerFeed.startsWith("Your feed")); - assertEquals("should be unsubscribed", "Unsubscribed from @" + user.getName(), - commandsManager.processCommand(readerUser, "U @" + user.getName(), emptyUri) - .getText()); - assertEquals("number of readers should match", 0, - userService.getUserReaders(uid).size()); - assertEquals("number of friends should match", 1, - userService.getUserFriends(uid).size()); - assertEquals("should be unsubscribed", "Unsubscribed from #" + mid, - commandsManager.processCommand(readerUser, "u #" + mid, emptyUri).getText()); - assertEquals("number of subscribed users should match", 0, - subscriptionService.getUsersSubscribedToComments(messagesService.getMessage(mid), - messagesService.getReply(mid, rid)).size()); - assertNotEquals("should NOT be deleted", String.format("Message %s deleted", mid), - commandsManager.processCommand(readerUser, "D #" + mid, emptyUri).getText()); - assertEquals("should be deleted", "Message deleted", - commandsManager.processCommand(user, "D #" + mid, emptyUri).getText()); - assertEquals("should be not found", "Message not found", - commandsManager.processCommand(user, "#" + mid, emptyUri).getText()); - - String expectedCodeMessage = "some smelly code goes here\n" + - "> void main(void** args) {\n" + - "> }"; - String codeAndTags = "*code\n" + expectedCodeMessage; - Message codeAndTagsMessage = commandsManager.processCommand(user, codeAndTags, emptyUri).getNewMessage().get(); - List<Tag> codeAndTagsTags = codeAndTagsMessage.getTags(); - assertEquals("expected single tag", 1, - codeAndTagsTags.size()); - assertEquals("the single tag should be the 'code'", "code", - codeAndTagsTags.get(0).getName()); - assertEquals("and the message should be with a C-code and without tags", expectedCodeMessage, - codeAndTagsMessage.getText()); - CommandResult result = commandsManager.processCommand(user, "*one *two *three *four *five *six test", emptyUri); - assertThat(result.getNewMessage(), is(Optional.empty())); - assertThat(result.getText(), is("Sorry, 5 tags maximum.")); - result = commandsManager.processCommand(user, String.format("#%d *one *two *three *four *five *six", msg.getMid()), emptyUri); - assertThat(result.getNewMessage(), is(Optional.empty())); - assertThat(result.getText(), is("Tags are NOT updated (5 tags maximum?)")); - result = commandsManager.processCommand(user, "I'm very smart to post my login url there" + - "<https://juick.com/settings?hash=VTYZkKV8FWkmu6g1>", emptyUri); - assertThat(result.getNewMessage().isPresent(), is(true)); - assertFalse(result.getNewMessage().get().getText().contains("VTYZkKV8FWkmu6g1")); - result = commandsManager.processCommand(user, "*корм *juick_ppl *рационализм *? *мюсли а сколько микроморт в дневной порции сверхмюслей?", emptyUri); - assertTrue(result.getNewMessage().isPresent()); - String tags = "*Juick *Google *Google Play"; - String data = "Вчера отправлял *NSFW постинг в топ :)"; - result = commandsManager.processCommand(user, String.format("%s %s", tags, data), emptyUri); - assertThat(result.getNewMessage().get().getTags().size(), equalTo(3)); - assertThat(result.getNewMessage().get().getText(), equalTo(data)); - tags = "*\u041a\u0438\u0435\u0432 *\u044d\u043a\u043e\u043b\u043e\u0433\u0438\u044f"; - data = "* \u043c\u0443\u0441\u043e\u0440\\n\u0423 \u043c\u0435\u043d\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e 4-5 \u0431\u0443\u0442\u044b\u043b\u043e\u043a 1,5\u043b \u041f\u0415\u0422. \u041c\u043d\u0435 \u0433\u0435\u043c\u043e\u0440\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0438\u043b\u0438 \u043f\u043e 5\u043a\u0433 \u044d\u0442\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0437\u0442\u0438 \u0435\u0433\u043e \u0435\u0449\u0435 \u043a\u0443\u0434\u0430-\u0442\u043e.\\n\u041d\u0435, \u043d\u0443 \u0435\u0441\u0442\u044c \u043b\u044e\u0434\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442 \u0432\u0442\u043e\u0440\u0441\u044b\u0440\u044c\u0435 \u043f\u043e \u043c\u0443\u0441\u043e\u0440\u043a\u0430\u043c, \u0441\u0432\u0430\u043b\u043a\u0430\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0434\u0435\u043d\u044c\u0433\u0438 \u043d\u0443\u0436\u043d\u044b. \u0418 \u0431\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u043e\u044f\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b-\u043a\u043b\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043f\u043b\u0430\u0441\u0442\u0438\u043a\u0430, \u043d\u043e \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u0443\u0441\u043e\u0440 \u0432\u044b\u0432\u043e\u0437\u044f\u0442 \u043d\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u043b\u0438 \u043b\u044e\u0434\u0438 \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u0432\u044b\u043a\u0438\u0434\u044b\u0432\u0430\u044e\u0442 \u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0441\u043e\u0440\u0430, \u0442\u043e \u0432 \u0442\u043e\u0439 \u043a\u043b\u0435\u0442\u043a\u0435 \u0442\u043e\u0442 \u043c\u0443\u0441\u043e\u0440, \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043b\u0441\u044f \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445."; - result = commandsManager.processCommand(user, String.format("%s %s", tags, data), emptyUri); - assertThat(result.getNewMessage().get().getTags().size(), equalTo(2)); - assertThat(result.getNewMessage().get().getTags().get(0).getName(), equalTo("Киев")); - assertThat(result.getNewMessage().get().getText(), equalTo(data)); - result = commandsManager.processCommand(user, "S @unknown-user", emptyUri); - assertThat(result.getNewMessage(), is(Optional.empty())); - assertThat(result.getText(), is("User not found")); - } - @Test - public void mailParserTest() throws Exception { - String mail = "MIME-Version: 1.0\n" + - "Received: by 10.176.0.242 with HTTP; Fri, 16 Mar 2018 05:31:50 -0700 (PDT)\n" + - "In-Reply-To: <2891710.100@juick.com>\n" + - "References: <2891710.0@juick.com> <2891710.100@juick.com>\n" + - "Date: Fri, 16 Mar 2018 15:31:50 +0300\n" + - "Delivered-To: vitalyster@gmail.com\n" + - "Message-ID: <CAF+0zPD_YLVgYovajLqUFwkRAgJT+FzyQ2EzikQsPKsrnfKv-Q@mail.gmail.com>\n" + - "Subject: Re: New reply to TJ\n" + - "From: Vitaly Takmazov <vitalyster@gmail.com>\n" + - "To: Juick <juick@juick.com>\n" + - "Content-Type: multipart/alternative; boundary=\"001a11454886e42be5056786ca70\"\n" + - "\n" + - "--001a11454886e42be5056786ca70\n" + - "Content-Type: text/plain; charset=\"UTF-8\"\n" + - "\n" + - "s2313334\n" + - "\n" + - "--001a11454886e42be5056786ca70\n" + - "Content-Type: text/html; charset=\"UTF-8\"\n" + - "\n" + - "<div dir=\"ltr\">s2313334</div>\n" + - "\n" + - "--001a11454886e42be5056786ca70--"; - mockMvc.perform(post("/api/mail").with(httpBasic(juickName, juickPassword)).content(mail)) - .andExpect(status().isOk()); - } - - @Test - public void recommendTests() throws Exception { - - int mid = messagesService.createMessage(ugnich.getUid(), "to be liked", null, null); - String freefdHash = userService.getHashByUID(freefd.getUid()); - int freefdMid = messagesService.createMessage(freefd.getUid(), "to be not liked", null, null); - - mockMvc.perform(post("/api/like?mid=" + mid + "&hash=" + freefdHash)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.status", is("Message is added to your recommendations"))); - mockMvc.perform(get("/api/thread?mid=" + mid + "&hash=" + freefdHash)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].recommendations.length()", is(1))) - .andExpect(jsonPath("$[0].recommendations[0]", is(freefdName))); - mockMvc.perform(post("/api/like?mid=" + freefdMid + "&hash=" + freefdHash)) - .andExpect(status().isForbidden()); - } - - @Test - public void likesTests() throws Exception{ - int user_id = userService.createUser("dsds", "secret"); - String freefdHash = userService.getHashByUID(freefd.getUid()); - int mid1 = messagesService.createMessage(user_id, "yo", null, new ArrayList<>()); - - mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=2")) - .andExpect(status().isOk()); - - Message msg4 = messagesService.getMessage(mid1); - assertThat(msg4.getLikes(), is(0)); - assertThat(messagesService.getMessages(AnonymousUser.INSTANCE, Collections.singletonList(mid1)).get(0).getLikes(), is(0)); - Assert.assertEquals(1, msg4.getReactions().stream().filter(r -> r.getId() == 2) - .findFirst().orElseThrow(IllegalStateException::new).getCount()); - mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) - .andExpect(status().isOk()); - mockMvc.perform(post("/api/react?mid=" + mid1 + "&hash=" + freefdHash+ "&reactionId=1")) - .andExpect(status().isOk()); - assertThat(messagesService.getMessage(mid1).getLikes(), is(1)); - } - - @Test - public void lastReadTests() throws Exception { - jdbcTemplate.execute("DELETE FROM bl_users"); - assertThat(userService.isInBLAny(ugnich.getUid(), freefd.getUid()), is(false)); - int mid = messagesService.createMessage(ugnich.getUid(), "to be watched", null, null); - subscriptionService.subscribeMessage(messagesService.getMessage(mid), ugnich); - messagesService.createReply(mid, 0, freefd, "new reply", null); - BiFunction<User, Integer, Integer> lastRead = (user, m) -> jdbcTemplate.queryForObject( - "SELECT last_read_rid FROM subscr_messages WHERE suser_id=? AND message_id=?", - Integer.class, user.getUid(), m); - assertThat(lastRead.apply(ugnich, mid), is(0)); - assertThat(messagesService.getUnread(ugnich).size(), is(1)); - assertThat(messagesService.getUnread(ugnich).get(0), is(mid)); - messagesService.getReplies(ugnich, mid); - assertThat(lastRead.apply(ugnich, mid), is(1)); - assertThat(messagesService.getUnread(ugnich).size(), is(0)); - messagesService.setLastReadComment(ugnich, mid, 0); - assertThat(lastRead.apply(ugnich, mid), is(1)); - String ugnichHash = userService.getHashByUID(ugnich.getUid()); - int freefdrid = messagesService.createReply(mid, 0, freefd, "again", null); - mockMvc.perform(get(String.format("/api/thread/mark_read/%d-%d.gif?hash=%s", mid, freefdrid, ugnichHash))) - .andExpect(status().isOk()) - .andExpect(content().bytes(IOUtils.toByteArray( - Objects.requireNonNull(getClass().getClassLoader().getResource("Transparent.gif"))))); - assertThat(lastRead.apply(ugnich, mid), is(freefdrid)); - privacyQueriesService.blacklistUser(ugnich, freefd); - int newfreefdrid = messagesService.createReply(mid, 0, freefd, "from ban", null); - serverManager.processMessageEvent(new MessageEvent(this, messagesService.getReply(mid, newfreefdrid), - Collections.emptyList())); - assertThat(userService.isReplyToBL(ugnich, messagesService.getReply(mid, newfreefdrid)), is(true)); - // TODO: test event listeners correctly - Thread.sleep(2000L); - assertThat(lastRead.apply(ugnich, mid), is(newfreefdrid)); - privacyQueriesService.blacklistUser(ugnich, freefd); - newfreefdrid = messagesService.createReply(mid, 0, freefd, "after ban", null); - assertThat(lastRead.apply(ugnich, mid), lessThan(newfreefdrid)); - mockMvc.perform(get(String.format("/api/thread?mid=%d&hash=%s", mid, ugnichHash))) - .andExpect(status().isOk()); - assertThat(lastRead.apply(ugnich, mid), is(newfreefdrid)); - } - @Test - public void feedsShouldNotContainMessagesWithBannedTags() { - Tag banned = tagService.getTag("banned", true); - int mid = messagesService.createMessage(ugnich.getUid(), "yo", "jpg", - Collections.singletonList(banned)); - privacyQueriesService.blacklistTag(freefd, banned); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getAll(freefd.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - assertFalse(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getAll(ugnich.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getPhotos(freefd.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - assertFalse(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getPhotos(ugnich.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - jdbcTemplate.update("UPDATE messages SET popular=1 WHERE message_id=?", mid); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getPopular(freefd.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - assertFalse(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getPopular(ugnich.getUid(), 0)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getMyFeed(freefd.getUid(), 0, true)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - int newUid = userService.createUser("newUser", "12345"); - int newMid = messagesService.createMessage(newUid, "people", null, Collections.singletonList(banned)); - messagesService.recommendMessage(newMid, ugnich.getUid()); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getMyFeed(freefd.getUid(), 0, true)) - .stream().noneMatch(m -> m.getTags().contains(banned))); - tagService.updateTags(newMid, Collections.singletonList(banned)); - assertThat(messagesService.getMessage(newMid).getTags().size(), is(0)); - privacyQueriesService.blacklistUser(freefd, userService.getUserByUID(newUid).orElse(AnonymousUser.INSTANCE)); - assertTrue(messagesService.getMessages(AnonymousUser.INSTANCE, messagesService.getMyFeed(freefd.getUid(), 0, true)) - .stream().noneMatch(m -> m.getMid() == newMid)); - } - @Test - public void tagsShouldBeDeserializedFromXml() throws JAXBException { - XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() - .extensions(Extension.of(com.juick.Message.class)) - .build(); - XmppSession xmpp = new XmppSession("juick.com", configuration) { - @Override - public void connect(Jid from) { - - } - - @Override - public Jid getConnectedResource() { - return null; - } - }; - String tag = "<tag xmlns='http://juick.com/message'>yo</tag>"; - String xml = "<message xmlns='jabber:client' from='juick@juick.com' type='chat'><body>yo</body><juick mid='1' ts='2017-09-14' uid='1' uname='ugnich' xmlns='http://juick.com/message'><body>yo</body><user uid='1' uname='ugnich' xmlns='http://juick.com/user'/><tag>yo</tag><tag>people</tag></juick></message>"; - Unmarshaller unmarshaller = xmpp.createUnmarshaller(); - rocks.xmpp.core.stanza.model.Message xmppMessage = (rocks.xmpp.core.stanza.model.Message) unmarshaller.unmarshal(new StringReader(xml)); - Tag xmlTag = (Tag) unmarshaller.unmarshal(new StringReader(tag)); - assertThat(xmlTag.getName(), equalTo("yo")); - Message juickMessage = xmppMessage.getExtension(Message.class); - assertThat(juickMessage.getTags().get(0).getName(), equalTo("yo")); - } - @Test - public void messageParserSerializer() throws ParserConfigurationException, - IOException, SAXException, JAXBException { - Message msg = new Message(); - msg.setTags(MessageUtils.parseTags("test test" + (char) 0xA0 + "2 test3")); - assertEquals("First tag must be", "test", msg.getTags().get(0).getName()); - assertEquals("Third tag must be", "test3", msg.getTags().get(2).getName()); - assertEquals("Count of tags must be", 3, msg.getTags().size()); - Instant currentDate = Instant.now(); - msg.setTimestamp(currentDate); - String jsonMessage = jsonMapper.writeValueAsString(msg); - assertEquals("date should be in timestamp field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), - JsonPath.read(jsonMessage, "$.timestamp")); - - - JAXBContext context = JAXBContext - .newInstance(Message.class); - Marshaller m = context.createMarshaller(); - - StringWriter sw = new StringWriter(); - m.marshal(msg, sw); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(CharEncoding.UTF_8))); - Node juickNode = doc.getElementsByTagName("juick").item(0); - NamedNodeMap attrs = juickNode.getAttributes(); - assertEquals("date should be in ts field", DateFormattersHolder.getMessageFormatterInstance().format(currentDate), - attrs.getNamedItem("ts").getNodeValue()); - } - @Test - public void restTemplateTests() { - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - MultiValueMap<String, String> map= new LinkedMultiValueMap<>(); - HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers); - - map.add("body", "yo"); - map.add("hash", userService.getHashByUID(ugnich.getUid())); - ResponseEntity<CommandResult> result = restTemplate.postForEntity( - "/api/post", - request, CommandResult.class); - assertThat(result.getStatusCode(), is(HttpStatus.OK)); - } - @Test - public void emptyAuthenticatedPostShouldThrowBadRequest() throws Exception { - mockMvc.perform(post("/api/post") - .with(httpBasic(juickName, juickPassword))) - .andExpect(status().isBadRequest()); - } - @Test - public void attachmentSizeTests() throws URISyntaxException, IOException { - ImageUtils imageUtils = new ImageUtils(StringUtils.EMPTY, StringUtils.EMPTY); - Attachment attachment = imageUtils.getAttachment(new File(getClass().getClassLoader().getResource("Transparent.gif").toURI())); - assertThat(attachment.getHeight(), is(1)); - assertThat(attachment.getWidth(), is(1)); - } - @Test - public void meContainsAllInfo() throws Exception { - jdbcTemplate.update("DELETE FROM subscr_users"); - assertThat(userService.getUserReaders(ugnich.getUid()).size(), is(0)); - assertThat(userService.getUserFriends(ugnich.getUid()).size(), is(0)); - commandsManager.processCommand(freefd, "S @ugnich", emptyUri); - commandsManager.processCommand(ugnich, "S @freefd", emptyUri); - assertThat(userService.getUserReaders(ugnich.getUid()).size(), is(1)); - String hash = userService.getHashByUID(ugnich.getUid()); - mockMvc.perform(get("/api/me") - .with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(jsonPath("$.hash", is(hash))) - .andExpect(jsonPath("$.readers.length()", is(1))) - .andExpect(jsonPath("$.read.length()", is(1))); - } - @Test - public void feedsShouldNotContainBannedUsers() throws Exception { - commandsManager.processCommand(ugnich, "BL @freefd", emptyUri); - CommandResult result = commandsManager.processCommand(ugnich, "freefd - dick", emptyUri); - int mid = result.getNewMessage().get().getMid(); - commandsManager.processCommand(freefd, String.format("#%d ugnich - dick too", mid), emptyUri); - commandsManager.processCommand(juick, String.format("#%d/1 ban for a hour!", mid), emptyUri); - commandsManager.processCommand(juick, String.format("#%d freefd is here but it is hidden from you", mid), emptyUri); - assertThat(messagesService.getMessage(mid).getReplies(), is(3)); - Message reply = messagesService.getReply(mid, 3); - assertThat(userService.isReplyToBL(ugnich, reply), is(false)); - List<Message> replies = messagesService.getReplies(ugnich, mid); - assertThat(replies.size(), is(1)); - commandsManager.processCommand(freefd, String.format("#%d/3 hahaha!", mid), emptyUri); - assertThat(messagesService.getMessage(mid).getReplies(), is(4)); - replies = messagesService.getReplies(ugnich, mid); - assertThat(replies.size(), is(1)); - commandsManager.processCommand(juick, String.format("#%d/4 mmm?!", mid), emptyUri); - assertThat(messagesService.getMessage(mid).getReplies(), is(5)); - replies = messagesService.getReplies(ugnich, mid); - reply = messagesService.getReply(mid, 5); - assertThat(userService.isReplyToBL(ugnich, reply), is(true)); - assertThat(replies.size(), is(1)); - List<Message> msgs = messagesService.getMessages(ugnich, Collections.singletonList(mid)); - assertThat(msgs.get(0).getReplies(), is(1)); - commandsManager.processCommand(ugnich, "BL @freefd", emptyUri); - messagesService.setRead(ugnich, mid); - assertThat(messagesService.getReplies(ugnich, mid).size(), is(5)); - List<Message> nonblmsgs = messagesService.getMessages(ugnich, Collections.singletonList(mid)); - assertThat(nonblmsgs.get(0).getReplies(), is(5)); - commandsManager.processCommand(ugnich, "BL @freefd", emptyUri); - Tag tag = tagService.getTag("linux", true); - messagesService.createMessage(freefd.getUid(), "sux", null, Collections.singletonList(tag)); - assertThat(messagesService.getTag(tag.TID, freefd.getUid(), 0, 10).size(), is(1)); - assertThat(messagesService.getTag(tag.TID, ugnich.getUid(), 0, 10).size(), is(0)); - commandsManager.processCommand(ugnich, "BL @freefd", emptyUri); - } - @Test - public void cmykJpegShouldBeProcessedCorrectly() throws Exception { - CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", new ClassPathResource("cmyk.jpg").getURI()); - assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); - int mid = postJpgCmyk.getNewMessage().get().getMid(); - File originalFile = Paths.get(imgDir, "p", String.format("%d.jpg", mid)).toFile(); - assertThat(originalFile.exists(), is(true)); - File mediumFile = Paths.get(imgDir, "photos-1024", String.format("%d.jpg", mid)).toFile(); - assertThat(mediumFile.exists(), is(true)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getWidth(), is(2585)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getHeight(), is(3335)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getMedium().getHeight(), is(1024)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getSmall().getHeight(), is(512)); - } - @Test - public void JpegWithoutJfifShouldBeProcessedCorrectly() throws Exception { - CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", new ClassPathResource("nojfif.jpg").getURI()); - assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); - int mid = postJpgCmyk.getNewMessage().get().getMid(); - File originalFile = Paths.get(imgDir, "p", String.format("%d.jpg", mid)).toFile(); - assertThat(originalFile.exists(), is(true)); - File mediumFile = Paths.get(imgDir, "photos-1024", String.format("%d.jpg", mid)).toFile(); - assertThat(mediumFile.exists(), is(true)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getWidth(), is(3264)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getHeight(), is(2448)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getMedium().getHeight(), is(768)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachment().getSmall().getHeight(), is(384)); - } - @Test - public void JpegFromJuickUriShouldBeProcessedCorrectly() throws Exception { - Path tmpFile = Paths.get(tmpDir, "2915104.jpg"); - Files.copy(Paths.get(ClassLoader.getSystemResource("2915104.jpg").toURI()), tmpFile, StandardCopyOption.REPLACE_EXISTING); - assertThat(tmpFile.toFile().exists(), is(true)); - CommandResult postJpgiPhone = commandsManager.processCommand(ugnich, "YO", URI.create("juick://2915104.jpg")); - assertThat(postJpgiPhone.getNewMessage().isPresent(), is(true)); - int mid = postJpgiPhone.getNewMessage().get().getMid(); - File originalFile = Paths.get(imgDir, "p", String.format("%d.jpg", mid)).toFile(); - assertThat(originalFile.exists(), is(true)); - File mediumFile = Paths.get(imgDir, "photos-1024", String.format("%d.jpg", mid)).toFile(); - assertThat(mediumFile.exists(), is(true)); - assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getWidth(), is(1280)); - assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getHeight(), is(1280)); - assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getMedium().getHeight(), is(1024)); - assertThat(postJpgiPhone.getNewMessage().get().getAttachment().getSmall().getHeight(), is(512)); - } - @Test - public void changeExtensionWhenReceiveFileWithWrongContentType() throws Exception { - Path pngOutput = Paths.get(tmpDir, "cmyk.png"); - Files.deleteIfExists(pngOutput); - Files.copy(getClass().getClassLoader().getResourceAsStream("cmyk.jpg"), pngOutput); - assertThat(pngOutput.toFile().exists(), is(true)); - CommandResult postJpgCmyk = commandsManager.processCommand(ugnich, "YO", pngOutput.toUri()); - assertThat(postJpgCmyk.getNewMessage().isPresent(), is(true)); - assertThat(postJpgCmyk.getNewMessage().get().getAttachmentType(), is("jpg")); - CommandResult replyJpgCmyk = commandsManager.processCommand(ugnich, String.format("#%d YO", postJpgCmyk.getNewMessage().get().getMid()), pngOutput.toUri()); - assertThat(replyJpgCmyk.getNewMessage().isPresent(), is(true)); - assertThat(replyJpgCmyk.getNewMessage().get().getAttachmentType(), is("jpg")); - } - @Test - public void messageEditingSpec() throws Exception { - MvcResult result = mockMvc.perform(post("/api/post").with(httpBasic(ugnichName, ugnichPassword)) - .param("body", "YO")).andExpect(status().is2xxSuccessful()).andReturn(); - Message original = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class) - .getNewMessage().get(); - assertThat(original.getText(), equalTo("YO")); - assertThat(original.getUpdatedAt(), equalTo(original.getTimestamp())); - // to have updated_at greater than ts - Thread.sleep(1000); - result = mockMvc.perform(post("/api/update").with(httpBasic(ugnichName, ugnichPassword)) - .param("mid", String.valueOf(original.getMid())) - .param("body", "PEOPLE")).andExpect(status().is2xxSuccessful()).andReturn(); - Message edited = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class) - .getNewMessage().get(); - assertThat(edited.getText(), equalTo("PEOPLE")); - assertThat(edited.getUpdatedAt(), greaterThan(edited.getTimestamp())); - mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword)) - .param("mid", String.valueOf(original.getMid())) - .param("body", "PEOPLE")).andExpect(status().is(403)); - result = mockMvc.perform(post("/api/comment").with(httpBasic(freefdName, freefdPassword)) - .param("mid", String.valueOf(original.getMid())) - .param("body", "HEY")).andExpect(status().is2xxSuccessful()).andReturn(); - CommandResult comment = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class); - assertThat(comment.getNewMessage().get().getText(), is("HEY")); - assertThat(comment.getNewMessage().get().getUpdatedAt(), is(comment.getNewMessage().get().getTimestamp())); - // to have updated_at greater than ts - Thread.sleep(1000); - result = mockMvc.perform(post("/api/update").with(httpBasic(freefdName, freefdPassword)) - .param("mid", String.valueOf(comment.getNewMessage().get().getMid())) - .param("rid", String.valueOf(comment.getNewMessage().get().getRid())) - .param("body", "HEY, JOE")).andExpect(status().is2xxSuccessful()).andReturn(); - Message editedComment = jsonMapper.readValue(result.getResponse().getContentAsString(), CommandResult.class) - .getNewMessage().get(); - assertThat(editedComment.getText(), is("HEY, JOE")); - assertThat(editedComment.getUpdatedAt(), greaterThan(editedComment.getTimestamp())); - messagesService.deleteMessage(ugnich.getUid(), original.getMid()); - } - @Test - public void subscribersToRecommendations() { - int readerId = userService.createUser("reader", "123456"); - int recommenderId = userService.createUser("recommender", "123456"); - int lateRecommenderId = userService.createUser("lateRecommender", "123456"); - int posterId = userService.createUser("poster", "123456"); - User reader = userService.getUserByName("reader"); - User recommender = userService.getUserByName("recommender"); - User lateRecommender = userService.getUserByName("lateRecommender"); - User poster = userService.getUserByName("poster"); - subscriptionService.subscribeUser(reader, recommender); - subscriptionService.subscribeUser(reader, lateRecommender); - Tag sampleTag = tagService.getTag("banned", true); - int posterMid = messagesService.createMessage(posterId, "YO", null, Collections.singletonList(sampleTag)); - messagesService.recommendMessage(posterMid, recommenderId); - BiFunction<Integer, Message, List<User>> subscribers = (recommId, msg) -> - subscriptionService.getUsersSubscribedToUserRecommendations(recommId, msg); - List<User> recommendSubscribers = subscribers.apply(recommenderId, messagesService.getMessage(posterMid)); - assertThat(recommendSubscribers.size(), is(1)); - assertThat(recommendSubscribers.get(0).getUid(), is(readerId)); - privacyQueriesService.blacklistUser(reader, poster); - assertThat(subscribers.apply(recommenderId, messagesService.getMessage(posterMid)).size(), is(0)); - privacyQueriesService.blacklistUser(reader, poster); - assertThat(subscribers.apply(recommenderId, messagesService.getMessage(posterMid)).size(), is(1)); - tagService.blacklistTag(reader, sampleTag); - assertThat(subscribers.apply(recommenderId, messagesService.getMessage(posterMid)).size(), is(0)); - tagService.blacklistTag(reader, sampleTag); - assertThat(subscribers.apply(recommenderId, messagesService.getMessage(posterMid)).size(), is(1)); - messagesService.recommendMessage(posterMid, lateRecommenderId); - List<User> lateRecommendSubscribers = subscribers.apply(recommenderId, messagesService.getMessage(posterMid)); - assertThat(lateRecommendSubscribers.size(), is(0)); - int readerMid = messagesService.createMessage(readerId, "PEOPLE", null, null); - messagesService.recommendMessage(readerMid, recommenderId); - assertThat(subscribers.apply(recommenderId, messagesService.getMessage(readerMid)).size(), is(0)); - } - @Test - public void mentionsInComments() { - int posterId = userService.createUser("p", "secret"); - int commenterId = userService.createUser("cc", "secret"); - User commenter = userService.getUserByUID(commenterId).get(); - int mentionerId = userService.createUser("mmm", "secret"); - User mentioner = userService.getUserByUID(mentionerId).get(); - int mid = messagesService.createMessage(posterId, "who is dick?", null, null); - Message msg = messagesService.getMessage(mid); - int rid = messagesService.createReply(mid, 0, commenter, - "@mmm is dick", null); - Message reply = messagesService.getReply(mid, rid); - assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(1)); - subscriptionService.subscribeUser(mentioner, commenter); - assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(1)); - privacyQueriesService.blacklistUser(mentioner, commenter); - assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(0)); - } - @Test - public void xmppStatusApi() throws Exception { - Supplier<XMPPStatus> getStatus = () -> { - try { - MvcResult result = mockMvc.perform(get("/api/xmpp-status").with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()).andReturn(); - return jsonMapper.readValue(result.getResponse().getContentAsString(), XMPPStatus.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - }; - assertThat(getStatus.get().getInbound(), is(nullValue())); - ConnectionIn test = new ConnectionIn(server, new Socket("localhost", server.getServerPort())); - test.from.add(Jid.of("test")); - server.getInConnections().clear(); - server.addConnectionIn(test); - assertThat(getStatus.get().getInbound().size(), is(1)); - } - @Test - public void credentialsShouldNeverBeSerialized() throws Exception { - int uid = userService.createUser("yyy", "xxxx"); - User yyy = userService.getUserByUID(uid).get(); - assertThat(yyy.getCredentials(), is("xxxx")); - ObjectMapper jsonMapper = new ObjectMapper(); - jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); - String jsonUser = jsonMapper.writeValueAsString(yyy); - Map<String, Object> user = JsonPath.read(jsonUser, "$"); - // only uid, name and uri - assertThat(user.keySet().size(), is(3)); - - JAXBContext context = JAXBContext - .newInstance(User.class); - Marshaller m = context.createMarshaller(); - - StringWriter sw = new StringWriter(); - m.marshal(yyy, sw); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(new ByteArrayInputStream(sw.toString().getBytes(StandardCharsets.UTF_8))); - Element juickNode = doc.getDocumentElement(); - NamedNodeMap attrs = juickNode.getAttributes(); - // uid, name, xmlns, xmlns:user - assertThat(attrs.getLength(), is(4)); - } - @Test - public void bannedUserBlogandPostShouldReturn404() throws Exception { - String userName = "isilmine"; - String userPassword = "secret"; - String msgText = "автор этого поста был забанен"; - - User isilmine = userService.getUserByUID(userService.createUser(userName, userPassword)).orElseThrow(IllegalStateException::new); - int mid = messagesService.createMessage(isilmine.getUid(), msgText, null, null); - mockMvc.perform(get(String.format("/api/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()); - jdbcTemplate.update("UPDATE users SET banned=1 WHERE id=?", isilmine.getUid()); - mockMvc.perform(get(String.format("/api/thread?mid=%d", mid)).with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isNotFound()); - mockMvc.perform(get("/api/messages?uname=isilmine").with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isNotFound()); - mockMvc.perform(get("/api/info/isilmine").with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isNotFound()); - mockMvc.perform(get("/api/info/ugnich").with(httpBasic(ugnichName, ugnichPassword))) - .andExpect(status().isOk()); - } - - @Test - public void emptyPasswordMeansUserIsDisabled() throws Exception { - String userName = "oldschooluser"; - String userPassword = ""; - - userService.createUser(userName, userPassword); - - mockMvc.perform(get("/api/auth").with(httpBasic(userName, userPassword))).andExpect(status().isUnauthorized()); - mockMvc.perform(post("/login") - .param("username", userName) - .param("password", userPassword)).andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/login?error=1")); - } - @Test - public void bannedUserShouldBeShadowedFromRecommendationsList() throws IOException { - int ermineId = userService.createUser("ermine", "secret"); - int monstreekId = userService.createUser("monstreek", "secret"); - int pogoId = userService.createUser("pogo", "secret"); - int fmapId = userService.createUser("fmap", "secret"); - int mid = messagesService.createMessage(monstreekId, "KURWA", null, null); - assertThat(messagesService.recommendMessage(mid, ermineId), is(MessagesService.RecommendStatus.Added)); - assertThat(messagesService.recommendMessage(mid, fmapId), is(MessagesService.RecommendStatus.Added)); - assertThat(messagesService.recommendMessage(mid, pogoId), is(MessagesService.RecommendStatus.Added)); - assertThat(messagesService.getMessage(mid).getLikes(), is(3)); - assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine", "pogo")), is(true)); - privacyQueriesService.blacklistUser(userService.getUserByName("monstreek"), userService.getUserByName("pogo")); - assertThat(messagesService.getMessage(mid).getLikes(), is(3)); - assertThat(CollectionUtils.isEqualCollection(messagesService.getMessageRecommendations(mid), Arrays.asList("fmap", "ermine")), is(true)); - } - @Test - public void bannedUserShouldNotBeVisibleToOthers() { - jdbcTemplate.execute("DELETE FROM messages"); - int casualUserId = userService.createUser("user", "secret"); - int bannedUserId = userService.createUser("banned", "banned"); - jdbcTemplate.update("UPDATE users SET banned=1 WHERE id=?", bannedUserId); - messagesService.createMessage(bannedUserId, "KURWA", null, Collections.emptyList()); - assertThat(messagesService.getAll(casualUserId, 0).size(), is(0)); - assertThat(messagesService.getDiscussions(casualUserId, 0L).size(), is(0)); - assertThat(messagesService.getDiscussions(0, 0L).size(), is(0)); - assertThat(messagesService.getAll(bannedUserId, 0).size(), is(1)); - int mid = messagesService.createMessage(casualUserId, "PEACE", null, Collections.emptyList()); - User banned = userService.getUserByName("banned"); - int bannedRid = messagesService.createReply(mid, 0, banned, "KURWA", null); - int casualRid = messagesService.createReply(mid, 0, userService.getUserByName("user"), "DOOR", null); - assertThat(messagesService.getReplies(AnonymousUser.INSTANCE, mid).size(), is(1)); - assertThat(messagesService.getMessages(AnonymousUser.INSTANCE, Collections.singletonList(mid)).get(0).getReplies(), is(1)); - assertThat(messagesService.getReplies(banned, mid).size(), is(2)); - assertThat(messagesService.getMessages(banned, Collections.singletonList(mid)).get(0).getReplies(), is(2)); - } - - @Test - public void accountUrlShouldBeExposedOverWebfinger() throws Exception { - mockMvc.perform(get("/.well-known/webfinger?resource=acct:ugnich@localhost")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.subject", is("acct:ugnich@localhost"))) - .andExpect(jsonPath("$.links", hasSize(1))) - .andExpect(jsonPath("$.links[0].href", is("http://localhost:8080/u/ugnich"))); - mockMvc.perform(get("/.well-known/webfinger?resource=acct:durov@localhost")) - .andExpect(status().isNotFound()); - Person ugnich = (Person) signatureManager.discoverPerson("ugnich@juick.com").get(); - assertThat(ugnich.getName(), is(ugnichName)); - } - @Test - public void userProfileAndBlogShouldBeExposedAsActivityStream() throws Exception { - mockMvc.perform(get("/u/ugnich").accept(Context.LD_JSON_MEDIA_TYPE)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.icon.url", is("http://localhost:8080/i/a/1.png"))) - .andExpect(jsonPath("$.publicKey.publicKeyPem", is(keystoreManager.getPublicKeyPem()))); - jdbcTemplate.execute("DELETE FROM messages"); - List<Integer> mids = IteratorUtils.toList(IntStream.rangeClosed(1, 30) - .mapToObj(i -> messagesService.createMessage(ugnich.getUid(), - String.format("message %d", i), null, null)) - .collect(Collectors.toCollection(ArrayDeque::new)).descendingIterator()); - List<Integer> midsPage = mids.stream().limit(20).collect(Collectors.toList()); - mockMvc.perform(get("/u/ugnich/blog").accept(Context.ACTIVITYSTREAMS_PROFILE_MEDIA_TYPE)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.orderedItems", hasSize(20))) - .andExpect(jsonPath("$.next", is("http://localhost:8080/u/ugnich/blog?before=" + midsPage.get(midsPage.size() - 1)))); - } - @Test - public void postWithoutTagsShouldNotHaveAsteriskInTitle() throws Exception { - String msgText = "Привет, я - Угнич"; - int mid = messagesService.createMessage(ugnich.getUid(), msgText, null, null); - HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); - assertThat(threadPage.getTitleText(), equalTo("ugnich:")); - } - @Test - public void repliesList() throws IOException { - int mid = messagesService.createMessage(ugnich.getUid(), "hello", null, null); - IntStream.range(1, 15).forEach(i -> - messagesService.createReply(mid, i-1, freefd, String.valueOf(i-1), null )); - - HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); - assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); - Long visibleItems = StreamSupport.stream(threadPage.getHtmlElementById("replies") - .getChildElements().spliterator(), false).filter(e -> { - StyleElement display = e.getStyleElement("display"); - return display == null || !display.getValue().equals("none"); - }).count(); - assertThat(visibleItems, equalTo(14L)); - } - @Test - public void userShouldNotSeeReplyButtonToBannedUser() throws Exception { - int mid = messagesService.createMessage(ugnich.getUid(), "freefd bl me", null, null); - messagesService.createReply(mid, 0, ugnich, "yo", null); - MvcResult loginResult = mockMvc.perform(post("/login") - .param("username", freefdName) - .param("password", freefdPassword)) - .andExpect(status().isFound()).andReturn(); - Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); - webClient.setCookieManager(new CookieManager()); - webClient.getCookieManager().addCookie( - new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), - loginCookie.getName(), - loginCookie.getValue())); - HtmlPage threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); - assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); - assertThat(threadPage.querySelectorAll(".msg-comment-target").isEmpty(), equalTo(false)); - assertThat(threadPage.querySelectorAll(".a-thread-comment").isEmpty(), equalTo(false)); - privacyQueriesService.blacklistUser(freefd, ugnich); - assertThat(userService.isInBLAny(freefd.getUid(), ugnich.getUid()), equalTo(true)); - int renhaId = userService.createUser("renha", "secret"); - messagesService.createReply(mid, 0, userService.getUserByUID(renhaId).orElseThrow(IllegalStateException::new), - "people", null); - threadPage = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); - assertThat(threadPage.getWebResponse().getStatusCode(), equalTo(200)); - assertThat(threadPage.querySelectorAll(".msg-comment-target").isEmpty(), equalTo(true)); - assertThat(threadPage.querySelectorAll(".a-thread-comment").isEmpty(), equalTo(true)); - } - @Test - public void correctTagsEscaping() throws PebbleException, IOException { - PebbleTemplate template = pebbleEngine.getTemplate("views/test"); - Writer writer = new StringWriter(); - template.evaluate(writer, - Collections.singletonMap("tagsList", - Collections.singletonList(StringEscapeUtils.escapeHtml4(new Tag(">_<").getName())))); - String output = writer.toString().trim(); - assertThat(output, equalTo("<a href=\"/ugnich/?tag=%26gt%3B_%26lt%3B\">>_<</a>")); - } - - public DomElement fetchMeta(String url, String name) throws IOException { - HtmlPage page = webClient.getPage(url); - DomElement emptyMeta = new DomElement("", "meta", null, null); - return page.getElementsByTagName("meta").stream() - .filter(t -> t.getAttribute("name").equals(name)).findFirst().orElse(emptyMeta); - } - @Test - public void testTwitterCards() throws Exception { - - int mid = messagesService.createMessage(ugnich.getUid(), "without image", null, null); - - assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid), "twitter:card") - .getAttribute("content"), equalTo("summary")); - int mid2 = messagesService.createMessage(ugnich.getUid(), "with image", "png", null); - Message message = messagesService.getMessage(mid2); - assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid2), "twitter:card") - .getAttribute("content"), equalTo("summary_large_image")); - assertThat(fetchMeta(String.format("http://localhost:8080/ugnich/%d", mid2), "og:description") - .getAttribute("content"), - startsWith(StringEscapeUtils.escapeHtml4(MessageUtils.getMessageHashTags(message)))); - } - @Test - public void hashLoginShouldNotUseSession() throws Exception { - String hash = userService.getHashByUID(ugnich.getUid()); - MvcResult hashLoginResult = mockMvc.perform(get("/?show=my&hash=" + hash)) - .andExpect(status().isOk()) - .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) - .andExpect(content().string(containsString(hash))) - .andReturn(); - Cookie rememberMeFromHash = hashLoginResult.getResponse().getCookie("juick-remember-me"); - MvcResult formLoginResult = mockMvc.perform(post("/login") - .param("username", ugnichName) - .param("password", ugnichPassword)) - .andExpect(status().is3xxRedirection()).andReturn(); - Cookie rememberMeFromForm = formLoginResult.getResponse().getCookie("juick-remember-me"); - mockMvc.perform(get("/?show=my").cookie(rememberMeFromForm)).andExpect(status().isOk()) - .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) - .andExpect(content().string(containsString(hash))); - mockMvc.perform(get("/?show=my").cookie(rememberMeFromHash)).andExpect(status().isOk()) - .andExpect(model().attribute("visitor", hasProperty("authHash", equalTo(hash)))) - .andExpect(content().string(containsString(hash))); - } - @Test - public void nonExistentBlogShouldReturn404() throws Exception { - mockMvc.perform(get("/ololoe/")).andExpect(status().isNotFound()); - } - @Test - public void discussionsShouldBePageableByTimestamp() throws Exception { - String msgText = "Привет, я снова Угнич"; - int mid = messagesService.createMessage(ugnich.getUid(), msgText, null, null); - int midNew = messagesService.createMessage(ugnich.getUid(), "Я более новый Угнич", null, null); - MvcResult loginResult = mockMvc.perform(post("/login") - .param("username", freefdName) - .param("password", freefdPassword)) - .andExpect(status().is3xxRedirection()).andReturn(); - Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); - webClient.setCookieManager(new CookieManager()); - webClient.getCookieManager().addCookie( - new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), - loginCookie.getName(), - loginCookie.getValue())); - String discussionsUrl = "http://localhost:8080/"; - HtmlPage discussions = webClient.getPage(discussionsUrl); - assertThat(discussions.querySelectorAll("article").size(), is(0)); - subscriptionService.subscribeMessage(messagesService.getMessage(mid), freefd); - discussions = (HtmlPage) discussions.refresh(); - assertThat(discussions.querySelectorAll("article").size(), is(1)); - subscriptionService.subscribeMessage(messagesService.getMessage(midNew), freefd); - discussions = (HtmlPage) discussions.refresh(); - assertThat(discussions.querySelectorAll("article").size(), is(2)); - assertThat(discussions.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); - messagesService.createReply(mid, 0, freefd, "I'm replied", null); - discussions = (HtmlPage) discussions.refresh(); - assertThat(discussions.querySelectorAll("article").size(), is(2)); - assertThat(discussions.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); - Message msg = messagesService.getMessage(mid); - HtmlPage discussionsOld = webClient.getPage(discussionsUrl + "?to=" + msg.getUpdated().toEpochMilli()); - assertThat(discussionsOld.querySelectorAll("article").size(), is(1)); - assertThat(discussionsOld.querySelectorAll("article").get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); - List<Integer> newMids = IntStream.rangeClosed(1, 19).map(i -> messagesService.createMessage(ugnich.getUid(), String.valueOf(i), null, null)).boxed().collect(Collectors.toList()); - for (Integer m : newMids) { - subscriptionService.subscribeMessage(messagesService.getMessage(m), freefd); - } - discussions = (HtmlPage) discussions.refresh(); - assertThat(discussions.querySelectorAll("article").size(), is(20)); - assertThat(discussions.querySelectorAll("article") - .get(19).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); - messagesService.createReply(midNew, 0, freefd, "I'm replied", null); - discussions = (HtmlPage) discussions.refresh(); - assertThat(discussions.querySelectorAll("article") - .get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(midNew))); - Message old = messagesService.getMessage(newMids.get(0)); - discussionsOld = webClient.getPage(discussionsUrl + "?to=" + old.getUpdated().toEpochMilli()); - assertThat(discussionsOld.querySelectorAll("article").size(), is(1)); - assertThat(discussionsOld.querySelectorAll("article") - .get(0).getAttributes().getNamedItem("data-mid").getNodeValue(), is(String.valueOf(mid))); - } - @Test - public void redirectParamShouldCorrectlyRedirectLoggedUser() throws Exception { - MvcResult formLoginResult = mockMvc.perform(post("/login") - .param("username", ugnichName) - .param("password", ugnichPassword)) - .andExpect(status().isFound()).andReturn(); - Cookie rememberMeFromForm = formLoginResult.getResponse().getCookie("juick-remember-me"); - mockMvc.perform(get("/login").cookie(rememberMeFromForm)) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/")); - mockMvc.perform(get("/login?redirect=false").cookie(rememberMeFromForm)) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/login/success")); - } - @Test - public void anythingRedirects() throws Exception { - int mid = messagesService.createMessage(ugnich.getUid(), "yo", null, null); - mockMvc.perform(get(String.format("/%d", mid))) - .andExpect(status().isMovedPermanently()) - .andExpect(redirectedUrl(String.format("/%s/%d", ugnich.getName(), mid))); - } - @Test - public void appAssociationsTest() throws Exception { - mockMvc.perform((get("/.well-known/apple-app-site-association"))) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) - .andExpect(jsonPath("$.webcredentials.apps[0]", is(appId))); - } - @Test - public void notificationsTests() throws Exception { - jdbcTemplate.execute("DELETE FROM messages"); - jdbcTemplate.execute("DELETE FROM replies"); - jdbcTemplate.execute("DELETE FROM subscr_messages"); - MvcResult loginResult = mockMvc.perform(post("/login") - .param("username", freefdName) - .param("password", freefdPassword)) - .andExpect(status().is3xxRedirection()).andReturn(); - Cookie loginCookie = loginResult.getResponse().getCookie("juick-remember-me"); - webClient.setCookieManager(new CookieManager()); - webClient.getCookieManager().addCookie( - new com.gargoylesoftware.htmlunit.util.Cookie(loginCookie.getDomain(), - loginCookie.getName(), - loginCookie.getValue())); - int mid = messagesService.createMessage(ugnich.getUid(), "new test", null, null); - subscriptionService.subscribeMessage(messagesService.getMessage(mid), freefd); - int rid = messagesService.createReply(mid, 0, ugnich, "new reply", null); - HtmlPage discussionsPage = webClient.getPage("http://localhost:8080/?show=discuss"); - assertThat(discussionsPage.querySelectorAll("#global a .badge").size(), is(1)); - HtmlPage unreadThread = webClient.getPage(String.format("http://localhost:8080/ugnich/%d", mid)); - assertThat(unreadThread.querySelectorAll("#global a .badge").size(), is(0)); - } - @Test - public void escapeSqlTests() { - String sql = String.format("SELECT * FROM table WHERE data='%s'", Utils.encodeSphinx("';-- DROP TABLE table")); - assertThat(sql, is("SELECT * FROM table WHERE data='\\';-- DROP TABLE table\'")); - } - @Test - public void swaggerOutput() throws Exception { - MvcResult result = mockMvc.perform(get("/v2/api-docs") - .accept(MediaType.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()) - .andReturn(); - String outputDir = System.getProperty("io.springfox.staticdocs.outputDir"); - if (StringUtils.isNotEmpty(outputDir)) { - Files.createDirectories(Paths.get(outputDir)); - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8); - writer.write(result.getResponse().getContentAsString()); - writer.flush(); - } - } - @Test - public void newMessageShouldNotContainDuplicatedTags() throws Exception { - CommandResult result = commandsManager.processCommand(ugnich, "*test1 *test2 *test1 test3", emptyUri); - assertThat(result.getNewMessage().isPresent(), is(true)); - Message msg = result.getNewMessage().get(); - assertThat(msg.getTags().size(), is (2)); - assertThat(msg.getTags().get(0).getName(), is("test1")); - assertThat(msg.getTags().get(1).getName(), is("test2")); - assertThat(msg.getText(), is("test3")); - } - @Test - public void oneClickUnsubscribe() throws Exception { - mockMvc.perform(post("/settings/unsubscribe") - .param("hash", "123456") - .param("List-Unsubscribe", "One-Click")).andExpect(status().isBadRequest()); - mockMvc.perform(post("/settings/unsubscribe") - .param("hash", userService.getHashByUID(ugnich.getUid())) - .param("List-Unsubscribe", "One-Click")).andExpect(status().isOk()); - } - @Test - public void ActivityDeserialization() throws IOException { - String followJsonStr = IOUtils.toString(new ClassPathResource("follow.json").getURI(), StandardCharsets.UTF_8); - Follow follow = (Follow)jsonMapper.readValue(followJsonStr, Context.class); - String personJsonStr = IOUtils.toString(new ClassPathResource("person.json").getURI(), StandardCharsets.UTF_8); - Person person = (Person)jsonMapper.readValue(personJsonStr, Context.class); - String undoJsonStr = IOUtils.toString(new ClassPathResource("undo.json").getURI(), StandardCharsets.UTF_8); - Undo undo = jsonMapper.readValue(undoJsonStr, Undo.class); - String undoFollower = (String)((Map)undo.getObject()).get("object"); - String createJsonStr = IOUtils.toString(new ClassPathResource("create.json").getURI(), StandardCharsets.UTF_8); - Create create = jsonMapper.readValue(createJsonStr, Create.class); - Map<String, Object> note = (Map<String, Object>) create.getObject(); - Map<String, Object> attachmentObj = (Map<String, Object> )((List<Object>) note.get("attachment")).get(0); - String attachment = attachmentObj != null ? (String)attachmentObj.get("url") : StringUtils.EMPTY; - String deleteJsonStr = IOUtils.toString(new ClassPathResource("delete.json").getURI(), StandardCharsets.UTF_8); - Delete delete = jsonMapper.readValue(deleteJsonStr, Delete.class); - int mid = messagesService.createMessage(ugnich.getUid(), "YO", "", null); - User extUser = new User(); - extUser.setUri(URI.create("http://localhost:8080/users/xwatt")); - int rid = messagesService.createReply(mid, 0, extUser, "PEOPLE", null); - Message replyFromExt = messagesService.getReply(mid, rid); - String extMessageUri = "http://localhost:8080/statuses/12345"; - messagesService.updateReplyUri(replyFromExt, URI.create(extMessageUri)); - int rid2 = messagesService.createReply(mid, rid, ugnich, "HI", null); - - Message replyToExt = messagesService.getReply(mid, rid2); - Note replyNote = activityPubManager.makeNote(replyToExt); - assertThat(replyNote.getInReplyTo(), equalTo(extMessageUri)); - String noteStr = IOUtils.toString(new ClassPathResource("mention.json").getURI(), StandardCharsets.UTF_8); - Note create2 = jsonMapper.readValue(noteStr, Note.class); - jsonMapper.readValue(IOUtils.toString(new ClassPathResource("webfinger.json").getURI(), StandardCharsets.UTF_8), Account.class); - NodeInfo info = jsonMapper.readValue(IOUtils.toString(new ClassPathResource("xnodeinfo2.json").getURI(), StandardCharsets.UTF_8), NodeInfo.class); - assertThat(info.getUsage().getUsers().getActiveHalfyear(), is(42)); - } - @Test - public void activitySerialization() throws Exception { - Message msgNoTags = commandsManager.processCommand(ugnich, "people", emptyUri).getNewMessage().get(); - String json = jsonMapper.writeValueAsString(Context.build(activityPubManager.makeNote(msgNoTags))); - Message msg = commandsManager.processCommand(ugnich, "*shit happens", emptyUri).getNewMessage().get(); - Note note = activityPubManager.makeNote(msg); - json = jsonMapper.writeValueAsString(Context.build(note)); - Note replyNote = new Note(); - replyNote.setId("http://localhost:8080/n/2-1"); - replyNote.setInReplyTo(activityPubManager.messageUri(msg)); - replyNote.setAttributedTo("http://localhost:8080/u/freefd"); - replyNote.setTo(Collections.singletonList(activityPubManager.personUri(ugnich))); - replyNote.setContent("HI"); - Create create = new Create(); - create.setActor("http://localhost:8080/u/freefd"); - create.setObject(replyNote); - signatureManager.post((Person) signatureManager.getContext(URI.create("http://localhost:8080/u/freefd")).get(), - (Person) signatureManager.getContext(URI.create("http://localhost:8080/u/ugnich")).get(), create); - Message replyToExt = commandsManager.processCommand(ugnich, String.format("#%d/1 PSSH YOBA ETO TI", msg.getMid()), emptyUri).getNewMessage().get(); - json = jsonMapper.writeValueAsString(Context.build(activityPubManager.makeNote(messagesService.getReply(replyToExt.getMid(), replyToExt.getRid())))); - } - @Test - public void signingSpec() throws IOException { - Person from = (Person) signatureManager.getContext(URI.create("http://localhost:8080/u/freefd")).get(); - Person to = (Person) signatureManager.getContext(URI.create("http://localhost:8080/u/ugnich")).get(); - Follow follow = new Follow(); - follow.setActor("http://localhost:8080/u/freefd"); - follow.setObject("http://localhost:8080/u/ugnich"); - signatureManager.post(from, to, follow); - } - @Test - public void hostmeta() throws Exception { - MvcResult result = mockMvc.perform(get("/.well-known/host-meta")) - .andExpect(status().isOk()).andReturn(); - String xrd = result.getResponse().getContentAsString(); - result = mockMvc.perform(get("/.well-known/x-nodeinfo2")) - .andExpect(status().isOk()).andReturn(); - } - @Test - public void pms() throws Exception { - jdbcTemplate.execute("DELETE FROM pm"); - jdbcTemplate.execute("DELETE FROM bl_users"); - CommandResult res = commandsManager.processCommand(ugnich, "@freefd DICK", emptyUri); - assertThat(res.getNewMessage(), is(Optional.empty())); - assertThat(res.getText(), is("Private message sent")); - MvcResult result = mockMvc.perform(get("/api/groups_pms") - .with(httpBasic(freefdName, freefdPassword))) - .andExpect(status().isOk()) - .andReturn(); - PrivateChats chats = jsonMapper.readValue(result.getResponse().getContentAsString(), PrivateChats.class); - assertThat(chats.getUsers().size(), is(1)); - } - @Test - public void seenTests() { - Instant now = Instant.now(); - int newUserUid = userService.createUser("newuser", "assword"); - assertThat(userService.getUserByUID(newUserUid).get().getSeen(), is(nullValue())); - messagesService.createMessage(newUserUid, "YO", "", null); - assertThat(userService.getUserByUID(newUserUid).get().getSeen(), greaterThanOrEqualTo(now)); - } -} diff --git a/juick-server/src/test/resources/2915104.jpg b/juick-server/src/test/resources/2915104.jpg Binary files differdeleted file mode 100644 index 7f0fc3ba..00000000 --- a/juick-server/src/test/resources/2915104.jpg +++ /dev/null diff --git a/juick-server/src/test/resources/cmyk.jpg b/juick-server/src/test/resources/cmyk.jpg Binary files differdeleted file mode 100644 index 40af259c..00000000 --- a/juick-server/src/test/resources/cmyk.jpg +++ /dev/null diff --git a/juick-server/src/test/resources/create.json b/juick-server/src/test/resources/create.json deleted file mode 100644 index 42d20161..00000000 --- a/juick-server/src/test/resources/create.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"Create","id":"https://mastodon.social/users/xwatt/statuses/100850249548292153/activity","published":"2018-10-06T19:04:44Z","to":["https://www.w3.org/ns/activitystreams#Public"],"actor":"https://mastodon.social/users/xwatt","object":{"id":"https://mastodon.social/users/xwatt/statuses/100850249548292153","type":"Note","inReplyTo":"https://juick.com/m/2922602","published":"2018-10-06T19:04:44Z","url":"https://mastodon.social/@xwatt/100850249548292153","attributedTo":"https://mastodon.social/users/xwatt","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/xwatt/followers","https://juick.com/u/TJ"],"sensitive":false,"atomUri":"https://mastodon.social/users/xwatt/statuses/100850249548292153","inReplyToAtomUri":"https://juick.com/m/2922602","conversation":"tag:mastodon.social,2018-10-04:objectId=57333900:objectType=Conversation","content":"<p><span class=\"h-card\"><a href=\"https://juick.com/u/TJ\" class=\"u-url mention\">@<span>TJ</span></a></span> YO</p>","contentMap":{"en":"<p><span class=\"h-card\"><a href=\"https://juick.com/u/TJ\" class=\"u-url mention\">@<span>TJ</span></a></span> YO</p>"},"attachment":[{"type":"Document","mediaType":"image/jpeg","url":"https://files.mastodon.social/media_attachments/files/006/922/030/original/04057122ea7c6570.jpeg"}],"tag":[{"type":"Mention","href":"https://juick.com/u/TJ","name":"@TJ@juick.com"}]},"type":"Create","@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":{"@id":"as:movedTo","@type":"@id"},"Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","focalPoint":{"@container":"@list","@id":"toot:focalPoint"},"featured":{"@id":"toot:featured","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value"}]}
\ No newline at end of file diff --git a/juick-server/src/test/resources/data.sql b/juick-server/src/test/resources/data.sql deleted file mode 100644 index 102b11f4..00000000 --- a/juick-server/src/test/resources/data.sql +++ /dev/null @@ -1,8 +0,0 @@ -INSERT INTO tags(tag_id, name) VALUES(2, 'juick'); -INSERT INTO reactions (like_id, description) VALUES (1, 'like'); -INSERT INTO reactions (like_id, description) VALUES (2, 'love'); -INSERT INTO reactions (like_id, description) VALUES (3, 'lol'); -INSERT INTO reactions (like_id, description) VALUES (4, 'hmm'); -INSERT INTO reactions (like_id, description) VALUES (5, 'angry'); -INSERT INTO reactions (like_id, description) VALUES (6, 'uhblya'); -INSERT INTO reactions (like_id, description) VALUES (7, 'ugh'); diff --git a/juick-server/src/test/resources/delete.json b/juick-server/src/test/resources/delete.json deleted file mode 100644 index 9bd3fdea..00000000 --- a/juick-server/src/test/resources/delete.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"Delete","id":"https://mastodon.social/users/xwatt/statuses/100850777554564322#delete","to":["https://www.w3.org/ns/activitystreams#Public"],"actor":"https://mastodon.social/users/xwatt","object":{"id":"https://mastodon.social/users/xwatt/statuses/100850777554564322","type":"Tombstone","atomUri":"https://mastodon.social/users/xwatt/statuses/100850777554564322"},"type":"Delete","@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","movedTo":{"@id":"as:movedTo","@type":"@id"},"Hashtag":"as:Hashtag","ostatus":"http://ostatus.org#","atomUri":"ostatus:atomUri","inReplyToAtomUri":"ostatus:inReplyToAtomUri","conversation":"ostatus:conversation","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","focalPoint":{"@container":"@list","@id":"toot:focalPoint"},"featured":{"@id":"toot:featured","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value"}]}
\ No newline at end of file diff --git a/juick-server/src/test/resources/follow.json b/juick-server/src/test/resources/follow.json deleted file mode 100644 index 93d46c24..00000000 --- a/juick-server/src/test/resources/follow.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "https://mastodon.social/970f0d76-9ea7-46cd-a3e9-278e255f082d", - "type": "Follow", - "actor": "https://mastodon.social/users/xwatt", - "object": "https://x.juick.com/u/gegege", - "signature": { - "type": "RsaSignature2017", - "creator": "https://mastodon.social/users/xwatt#main-key", - "created": "2018-10-02T09:39:29Z", - "signatureValue": "lkxaKueSjT0nxCnT15hR8e1yQ7RsUCF0gBaiSAtXmN0tT3g7OcQPZUzUvCFF2aXB8xGFHMv+7Rp+jegR8rszuNRIghUxsOfYL5da2mD5UrpIlxiW4FxZjbni0klUF9GhRWfBYLIMumUsl9UElZPxtpYjlDQ7kCzYqnwbGgUiI0ehBJrHQJHET0pcyeSdGoRlXwD3I4c59nbr22CT026FBRNSJIxJj865ij5vg0j0q0/2ep+8ztya3x0+aYSrFn8WGO4Y2muCJtKurH2ROv8yyVgaIyFaUx6uvBf6pO3oGfWrm5if0P924LLlReXBItbleZrp0y2jPE7RriZsZmuFbg==" - } -}
\ No newline at end of file diff --git a/juick-server/src/test/resources/mention.json b/juick-server/src/test/resources/mention.json deleted file mode 100644 index c51265f1..00000000 --- a/juick-server/src/test/resources/mention.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "https://mastodonsocial.ru/users/inhosin/statuses/100946127454503070", - "type": "Note", - "summary": null, - "inReplyTo": "https://juick.com/n/2923741-40", - "published": "2018-10-23T17:27:45Z", - "url": "https://mastodonsocial.ru/@inhosin/100946127454503070", - "attributedTo": "https://mastodonsocial.ru/users/inhosin", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "https://mastodonsocial.ru/users/inhosin/followers", - "https://juick.com/u/vt" - ], - "sensitive": false, - "atomUri": "https://mastodonsocial.ru/users/inhosin/statuses/100946127454503070", - "inReplyToAtomUri": "https://juick.com/n/2923741-40", - "conversation": "tag:mastodonsocial.ru,2018-10-16:objectId=609790:objectType=Conversation", - "content": "<p><span class=\"h-card\"><a href=\"https://juick.com/vt/\" class=\"u-url mention\">@<span>vt</span></a></span> а лайки между серверами ходят? И ещё вопрос: нельзя всёже в ответ транслировать ник, чтобы нотификация поступала, а то приходится лопатить ленту что искать ответы. Я сейчас тоже с ActivityPub ковыряюсь.</p>", - "contentMap": { - "ru": "<p><span class=\"h-card\"><a href=\"https://juick.com/vt/\" class=\"u-url mention\">@<span>vt</span></a></span> а лайки между серверами ходят? И ещё вопрос: нельзя всёже в ответ транслировать ник, чтобы нотификация поступала, а то приходится лопатить ленту что искать ответы. Я сейчас тоже с ActivityPub ковыряюсь.</p>" - }, - "attachment": [], - "tag": [ - { - "type": "Mention", - "href": "https://juick.com/u/vt", - "name": "@vt@juick.com" - } - ] -}
\ No newline at end of file diff --git a/juick-server/src/test/resources/nojfif.jpg b/juick-server/src/test/resources/nojfif.jpg Binary files differdeleted file mode 100644 index 16ddec1b..00000000 --- a/juick-server/src/test/resources/nojfif.jpg +++ /dev/null diff --git a/juick-server/src/test/resources/person.json b/juick-server/src/test/resources/person.json deleted file mode 100644 index 67e88257..00000000 --- a/juick-server/src/test/resources/person.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "https://mastodon.social/users/xwatt", - "type": "Person", - "following": "https://mastodon.social/users/xwatt/following", - "followers": "https://mastodon.social/users/xwatt/followers", - "inbox": "https://mastodon.social/users/xwatt/inbox", - "outbox": "https://mastodon.social/users/xwatt/outbox", - "featured": "https://mastodon.social/users/xwatt/collections/featured", - "preferredUsername": "xwatt", - "name": "", - "summary": "\u003cp\u003e\u003c/p\u003e", - "url": "https://mastodon.social/@xwatt", - "manuallyApprovesFollowers": false, - "publicKey": { - "id": "https://mastodon.social/users/xwatt#main-key", - "owner": "https://mastodon.social/users/xwatt", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCYg1WrzerteFgLcbnRC\n1/pL5jFY05iuB4ycRlxxCpwpDihKdcmJ8nVEpFc/CIRtRRA3Oq1a+yF4L5X3Bwi8\nA8ajKHNtiPd4eeGdGvEJidf8cR8Bmfmrzt669Tmja+5Cr1CaFX9mYXhQoY6CqIxR\nDrPAAUb0CHJV+Ta6QkieCaGxYsvdg6Gg+8aw6k60vBswS6fmNsykH9xrovqtBb9M\ncKglyOA2W2FgswYtzRRKT5QQU4x/hfWMYuIEMhnke3U5k2gzb/qnJM2otaR0NzJ0\nkW+Fu7av5E6Ur1sUe1hTHpDxaAmNC+br19wTn6zh4Wt1UJp+Os56hBTSq50WKcfW\nhQIDAQAB\n-----END PUBLIC KEY-----\n" - }, - "tag": [], - "attachment": [], - "endpoints": { - "sharedInbox": "https://mastodon.social/inbox" - } -}
\ No newline at end of file diff --git a/juick-server/src/test/resources/templates/views/test.html b/juick-server/src/test/resources/templates/views/test.html deleted file mode 100644 index 7700be6f..00000000 --- a/juick-server/src/test/resources/templates/views/test.html +++ /dev/null @@ -1,2 +0,0 @@ -{% import "views/macros/tags" %} -{{ tags("ugnich", tagsList)}}
\ No newline at end of file diff --git a/juick-server/src/test/resources/undo.json b/juick-server/src/test/resources/undo.json deleted file mode 100644 index 371c6bd6..00000000 --- a/juick-server/src/test/resources/undo.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "movedTo": { - "@id": "as:movedTo", - "@type": "@id" - }, - "Hashtag": "as:Hashtag", - "ostatus": "http://ostatus.org#", - "atomUri": "ostatus:atomUri", - "inReplyToAtomUri": "ostatus:inReplyToAtomUri", - "conversation": "ostatus:conversation", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "focalPoint": { - "@container": "@list", - "@id": "toot:focalPoint" - }, - "featured": { - "@id": "toot:featured", - "@type": "@id" - }, - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "https://mastodon.social/users/xwatt#follows/1553133/undo", - "type": "Undo", - "actor": "https://mastodon.social/users/xwatt", - "object": { - "id": "https://mastodon.social/c5cfbc0b-3e4b-423a-aa51-1c38e1202371", - "type": "Follow", - "actor": "https://mastodon.social/users/xwatt", - "object": "https://x.juick.com/u/gegege" - }, - "signature": { - "type": "RsaSignature2017", - "creator": "https://mastodon.social/users/xwatt#main-key", - "created": "2018-10-02T10:27:33Z", - "signatureValue": "OOK3WDLgVMo6u1l/I1o4hrcOf12X2ryOa/xAeuYf7ncKQJbzFXohUYCrBtgUKjnOQJLHY/HbhhFE1SBXMCMUbPNF8KeztxWKqWnXtXNSHVv6Shxl+9yxZoGaAgpkYjn9qQGTAm4SXmV0RM49cz84PfLAJI1fUecoVclhVWXJuaSz4yZ/UteySjBMB5h5nPWGDmz4usviZ9EZTihr3xkFfkg+CPYwr5SYWDe5W1MxeKoosEck6Yhwt8OOf/eGB5guN81lp90O76oO6LGhblnYhMKxsOJf4ahF9qeCNajXk/qiwSfl6IwVADYlFB1GGTdIPXUUob5HhjX27Bpyah0lgA==" - } -}
\ No newline at end of file diff --git a/juick-server/src/test/resources/webfinger.json b/juick-server/src/test/resources/webfinger.json deleted file mode 100644 index 55f9e4f3..00000000 --- a/juick-server/src/test/resources/webfinger.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "subject": "acct:Gargron@mastodon.social", - "aliases": [ - "https://mastodon.social/@Gargron", - "https://mastodon.social/users/Gargron" - ], - "links": [ - { - "rel": "http://webfinger.net/rel/profile-page", - "type": "text/html", - "href": "https://mastodon.social/@Gargron" - }, - { - "rel": "http://schemas.google.com/g/2010#updates-from", - "type": "application/atom+xml", - "href": "https://mastodon.social/users/Gargron.atom" - }, - { - "rel": "self", - "type": "application/activity+json", - "href": "https://mastodon.social/users/Gargron" - }, - { - "rel": "salmon", - "href": "https://mastodon.social/api/salmon/1" - }, - { - "rel": "magic-public-key", - "href": "data:application/magic-public-key,RSA.vXc4vkECU2_CeuSo1wtnFoim94Ne1jBMYxTZ9wm2YTdJq1oiZKif06I2fOqDzY_4q_S9uccrE9Bkajv1dnkOVm31QjWlhVpSKynVxEWjVBO5Ienue8gND0xvHIuXf87o61poqjEoepvsQFElA5ymovljWGSA_jpj7ozygUZhCXtaS2W5AD5tnBQUpcO0lhItYPYTjnmzcc4y2NbJV8hz2s2G8qKv8fyimE23gY1XrPJg-cRF-g4PqFXujjlJ7MihD9oqtLGxbu7o1cifTn3xBfIdPythWu5b4cujNsB3m3awJjVmx-MHQ9SugkSIYXV0Ina77cTNS0M2PYiH1PFRTw==.AQAB" - }, - { - "rel": "http://ostatus.org/schema/1.0/subscribe", - "template": "https://mastodon.social/authorize_interaction?uri={uri}" - } - ] -} diff --git a/juick-server/src/test/resources/xnodeinfo2.json b/juick-server/src/test/resources/xnodeinfo2.json deleted file mode 100644 index 14be6394..00000000 --- a/juick-server/src/test/resources/xnodeinfo2.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.0", - "server": { - "baseUrl": "https://example.com", - "name": "Example diaspora* server", - "software": "diaspora", - "version": "0.5.0" - }, - "protocols": ["diaspora", "zot"], - "services": { - "inbound": ["gnusocial"], - "outbound": ["facebook", "twitter"] - }, - "openRegistrations": true, - "usage": { - "users": { - "total": 123, - "activeHalfyear": 42, - "activeMonth": 23 - }, - "localPosts": 500, - "localComments": 1000 - } -}
\ No newline at end of file diff --git a/juick-server/webpack.config.js b/juick-server/webpack.config.js deleted file mode 100644 index 8057ec15..00000000 --- a/juick-server/webpack.config.js +++ /dev/null @@ -1,74 +0,0 @@ -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const StyleLintPlugin = require('stylelint-webpack-plugin'); -const TerserPlugin = require('terser-webpack-plugin'); -const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); - -module.exports = (env, argv) => { - const dev = argv.mode !== 'production'; - const config = { - devtool: dev ? 'source-map' : false, - entry: { - 'scripts': [ - 'core-js/modules/es6.promise', - 'whatwg-fetch', - __dirname + '/src/main/assets/scripts.js', - require.resolve('evil-icons/assets/evil-icons.js') - ], - 'style': [ - __dirname + '/src/main/assets/style.css', - require.resolve('evil-icons/assets/evil-icons.css') - ] - }, - output: { - path: __dirname + '/src/main/resources/static', - filename: '[name].js' - }, - module: { - rules: [ - { test: /\.jsx?$/, loader: 'eslint-loader', enforce: 'pre', exclude: /node_modules/, options: { failOnWarning: false, failOnError: true, fix: true } }, - { test: /\.js$/, loader: 'babel-loader' }, - { - test: /\.css$/, - use: [ - MiniCssExtractPlugin.loader, - { - loader: 'css-loader' - }, - { - loader: 'postcss-loader', options: { - plugins: () => [ - require('autoprefixer')({}) - ] - } - } - ] - }, - { test: /\.png$/, loader: 'url-loader?limit=10000000000' }, - { test: /\.svg$/, loader: 'url-loader?limit=10000000000' } - ] - }, - plugins: [ - new StyleLintPlugin({ configFile: '.stylelintrc.json', context: 'src/main/assets', files: ['**/*.css'], emitErrors: false }), - new MiniCssExtractPlugin({ filename: 'style.css', allChunks: true }) - ], - }; - if (!dev) { - config.optimization = { - minimizer: [ - new TerserPlugin({ - cache: true, - parallel: true, - sourceMap: dev, - terserOptions: { - output: { - comments: /@license/i - } - }, - extractComments: true - }), - new OptimizeCSSAssetsPlugin({}) - ] - }; - } - return config; -}; diff --git a/juick-server/yarn.lock b/juick-server/yarn.lock deleted file mode 100644 index c7d19853..00000000 --- a/juick-server/yarn.lock +++ /dev/null @@ -1,6640 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/core@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e" - integrity sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.2" - "@babel/helpers" "^7.1.2" - "@babel/parser" "^7.1.2" - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.1.2" - convert-source-map "^1.1.0" - debug "^3.1.0" - json5 "^0.5.0" - lodash "^4.17.10" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.1.5.tgz#abb32d7aa247a91756469e788998db6a72b93090" - integrity sha512-vOyH020C56tQvte++i+rX2yokZcRfbv/kKcw+/BCRw/cK6dvsr47aCzm8oC1XHwMSEWbqrZKzZRLzLnq6SFMsg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.5" - "@babel/helpers" "^7.1.5" - "@babel/parser" "^7.1.5" - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.5" - "@babel/types" "^7.1.5" - convert-source-map "^1.1.0" - debug "^3.1.0" - json5 "^0.5.0" - lodash "^4.17.10" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0.tgz#1efd58bffa951dc846449e58ce3a1d7f02d393aa" - integrity sha512-/BM2vupkpbZXq22l1ALO7MqXJZH2k8bKVv8Y+pABFnzWdztDB/ZLveP5At21vLz5c2YtSE6p7j2FZEsqafMz5Q== - dependencies: - "@babel/types" "^7.0.0" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.2.tgz#fde75c072575ce7abbd97322e8fef5bae67e4630" - integrity sha512-70A9HWLS/1RHk3Ck8tNHKxOoKQuSKocYgwDN85Pyl/RBduss6AKxUR7RIZ/lzduQMSYfWEM4DDBu6A+XGbkFig== - dependencies: - "@babel/types" "^7.1.2" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.5.tgz#615f064d13d95f8f9157c7261f68eddf32ec15b3" - integrity sha512-IO31r62xfMI+wBJVmgx0JR9ZOHty8HkoYpQAjRWUGG9vykBTlGHdArZ8zoFtpUu2gs17K7qTl/TtPpiSi6t+MA== - dependencies: - "@babel/types" "^7.1.5" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-call-delegate@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" - integrity sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ== - dependencies: - "@babel/helper-hoist-variables" "^7.0.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-define-map@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" - integrity sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/types" "^7.0.0" - lodash "^4.17.10" - -"@babel/helper-explode-assignable-expression@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== - dependencies: - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== - dependencies: - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-get-function-arity@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-hoist-variables@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" - integrity sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-member-expression-to-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" - integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-module-imports@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-module-transforms@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" - integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - lodash "^4.17.10" - -"@babel/helper-optimise-call-expression@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - -"@babel/helper-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" - integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg== - dependencies: - lodash "^4.17.10" - -"@babel/helper-remap-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-wrap-function" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-replace-supers@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" - integrity sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-simple-access@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== - dependencies: - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helper-split-export-declaration@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" - integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== - dependencies: - "@babel/types" "^7.0.0" - -"@babel/helper-wrap-function@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" - integrity sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/template" "^7.1.0" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/helpers@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5" - integrity sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA== - dependencies: - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.1.2" - -"@babel/helpers@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.1.5.tgz#68bfc1895d685f2b8f1995e788dbfe1f6ccb1996" - integrity sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg== - dependencies: - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.5" - "@babel/types" "^7.1.5" - -"@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.0.tgz#a7cd42cb3c12aec52e24375189a47b39759b783e" - integrity sha512-SmjnXCuPAlai75AFtzv+KCBcJ3sDDWbIn+WytKw1k+wAtEy6phqI2RqKh/zAnw53i1NR8su3Ep/UoqaKcimuLg== - -"@babel/parser@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.2.tgz#85c5c47af6d244fab77bce6b9bd830e38c978409" - integrity sha512-x5HFsW+E/nQalGMw7hu+fvPqnBeBaIr0lWJ2SG0PPL2j+Pm9lYvCrsZJGIgauPIENx0v10INIyFjmSNUD/gSqQ== - -"@babel/parser@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.5.tgz#20b7d5e7e1811ba996f8a868962ea7dd2bfcd2fc" - integrity sha512-WXKf5K5HT6X0kKiCOezJZFljsfxKV1FpU8Tf1A7ZpGvyd/Q4hlrJm2EwoH2onaUq3O4tLDp+4gk0hHPsMyxmOg== - -"@babel/plugin-proposal-async-generator-functions@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" - integrity sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.0.0" - -"@babel/plugin-proposal-json-strings@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz#3b4d7b5cf51e1f2e70f52351d28d44fc2970d01e" - integrity sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.0.0" - -"@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz#9a17b547f64d0676b6c9cecd4edf74a82ab85e7e" - integrity sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - -"@babel/plugin-proposal-optional-catch-binding@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz#b610d928fe551ff7117d42c8bb410eec312a6425" - integrity sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz#498b39cd72536cd7c4b26177d030226eba08cd33" - integrity sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - regexpu-core "^4.2.0" - -"@babel/plugin-syntax-async-generators@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz#bf0891dcdbf59558359d0c626fdc9490e20bc13c" - integrity sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-json-strings@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz#0d259a68090e15b383ce3710e01d5b23f3770cbd" - integrity sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-object-rest-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" - integrity sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz#886f72008b3a8b185977f7cb70713b45e51ee475" - integrity sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" - integrity sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz#109e036496c51dd65857e16acab3bafdf3c57811" - integrity sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.1.0" - -"@babel/plugin-transform-block-scoped-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz#482b3f75103927e37288b3b67b65f848e2aa0d07" - integrity sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-block-scoping@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.1.5.tgz#3e8e0bc9a5104519923302a24f748f72f2f61f37" - integrity sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.10" - -"@babel/plugin-transform-classes@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz#ab3f8a564361800cbc8ab1ca6f21108038432249" - integrity sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-define-map" "^7.1.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz#2fbb8900cd3e8258f2a2ede909b90e7556185e31" - integrity sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-destructuring@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0.tgz#68e911e1935dda2f06b6ccbbf184ffb024e9d43a" - integrity sha512-Fr2GtF8YJSXGTyFPakPFB4ODaEKGU04bPsAllAIabwoXdFrPxL0LVXQX5dQWoxOjjgozarJcC9eWGsj0fD6Zsg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-dotall-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz#73a24da69bc3c370251f43a3d048198546115e58" - integrity sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - regexpu-core "^4.1.3" - -"@babel/plugin-transform-duplicate-keys@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz#a0601e580991e7cace080e4cf919cfd58da74e86" - integrity sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-exponentiation-operator@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz#9c34c2ee7fd77e02779cfa37e403a2e1003ccc73" - integrity sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-for-of@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" - integrity sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz#29c5550d5c46208e7f730516d41eeddd4affadbb" - integrity sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg== - dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-literals@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz#2aec1d29cdd24c407359c930cdd89e914ee8ff86" - integrity sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-modules-amd@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz#f9e0a7072c12e296079b5a59f408ff5b97bf86a8" - integrity sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-modules-commonjs@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" - integrity sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.1.0" - -"@babel/plugin-transform-modules-systemjs@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0.tgz#8873d876d4fee23209decc4d1feab8f198cf2df4" - integrity sha512-8EDKMAsitLkiF/D4Zhe9CHEE2XLh4bfLbb9/Zf3FgXYQOZyZYyg7EAel/aT2A7bHv62jwHf09q2KU/oEexr83g== - dependencies: - "@babel/helper-hoist-variables" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-modules-umd@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz#a29a7d85d6f28c3561c33964442257cc6a21f2a8" - integrity sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig== - dependencies: - "@babel/helper-module-transforms" "^7.1.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-new-target@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" - integrity sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-object-super@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz#b1ae194a054b826d8d4ba7ca91486d4ada0f91bb" - integrity sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - -"@babel/plugin-transform-parameters@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz#44f492f9d618c9124026e62301c296bf606a7aed" - integrity sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw== - dependencies: - "@babel/helper-call-delegate" "^7.1.0" - "@babel/helper-get-function-arity" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-regenerator@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" - integrity sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw== - dependencies: - regenerator-transform "^0.13.3" - -"@babel/plugin-transform-shorthand-properties@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" - integrity sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz#93583ce48dd8c85e53f3a46056c856e4af30b49b" - integrity sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-sticky-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz#30a9d64ac2ab46eec087b8530535becd90e73366" - integrity sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - -"@babel/plugin-transform-template-literals@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz#084f1952efe5b153ddae69eb8945f882c7a97c65" - integrity sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-typeof-symbol@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz#4dcf1e52e943e5267b7313bff347fdbe0f81cec9" - integrity sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-transform-unicode-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" - integrity sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" - regexpu-core "^4.1.3" - -"@babel/polyfill@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff" - integrity sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q== - dependencies: - core-js "^2.5.7" - regenerator-runtime "^0.11.1" - -"@babel/preset-env@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.1.5.tgz#a28b5482ca8bc2f2d0712234d6c690240b92495d" - integrity sha512-pQ+2o0YyCp98XG0ODOHJd9z4GsSoV5jicSedRwCrU8uiqcJahwQiOq0asSZEb/m/lwyu6X5INvH/DSiwnQKncw== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.1.0" - "@babel/plugin-proposal-json-strings" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.0.0" - "@babel/plugin-syntax-async-generators" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.1.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.1.5" - "@babel/plugin-transform-classes" "^7.1.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-dotall-regex" "^7.0.0" - "@babel/plugin-transform-duplicate-keys" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.1.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.1.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-amd" "^7.1.0" - "@babel/plugin-transform-modules-commonjs" "^7.1.0" - "@babel/plugin-transform-modules-systemjs" "^7.0.0" - "@babel/plugin-transform-modules-umd" "^7.1.0" - "@babel/plugin-transform-new-target" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.1.0" - "@babel/plugin-transform-parameters" "^7.1.0" - "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typeof-symbol" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - browserslist "^4.1.0" - invariant "^2.2.2" - js-levenshtein "^1.1.3" - semver "^5.3.0" - -"@babel/template@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.0.tgz#58cc9572e1bfe24fe1537fdf99d839d53e517e22" - integrity sha512-yZ948B/pJrwWGY6VxG6XRFsVTee3IQ7bihq9zFpM00Vydu6z5Xwg0C3J644kxI9WOTzd+62xcIsQ+AT1MGhqhA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@babel/template@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" - integrity sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.1.2" - "@babel/types" "^7.1.2" - -"@babel/traverse@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.0.tgz#503ec6669387efd182c3888c4eec07bcc45d91b2" - integrity sha512-bwgln0FsMoxm3pLOgrrnGaXk18sSM9JNf1/nHC/FksmNGFbYnPWY4GYCfLxyP1KRmfsxqkRpfoa6xr6VuuSxdw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.0.0" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - debug "^3.1.0" - globals "^11.1.0" - lodash "^4.17.10" - -"@babel/traverse@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.5.tgz#5aafca2039aa058c104cf2bfeb9fc4a857ccbca9" - integrity sha512-eU6XokWypl0MVJo+MTSPUtlfPePkrqsF26O+l1qFGlCKWwmiYAYy2Sy44Qw8m2u/LbPCsxYt90rghmqhYMGpPA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.5" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.5" - "@babel/types" "^7.1.5" - debug "^3.1.0" - globals "^11.1.0" - lodash "^4.17.10" - -"@babel/types@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0.tgz#6e191793d3c854d19c6749989e3bc55f0e962118" - integrity sha512-5tPDap4bGKTLPtci2SUl/B7Gv8RnuJFuQoWx26RJobS0fFrz4reUA3JnwIM+HVHEmWE0C1mzKhDtTp8NsWY02Q== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@babel/types@^7.1.2": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.2.tgz#183e7952cf6691628afdc2e2b90d03240bac80c0" - integrity sha512-pb1I05sZEKiSlMUV9UReaqsCPUpgbHHHu2n1piRm7JkuBkm6QxcaIzKu6FMnMtCbih/cEYTR+RGYYC96Yk9HAg== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@babel/types@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.5.tgz#12fe64e91a431234b7017b4227a78cc0eec4e081" - integrity sha512-sJeqa/d9eM/bax8Ivg+fXF7FpN3E/ZmTrWbkk6r+g7biVYfALMnLin4dKijsaqEhpd2xvOGfQTkQkD31YCVV4A== - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.stat@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz#54c5a964462be3d4d78af631363c18d6fa91ac26" - integrity sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw== - -"@webassemblyjs/ast@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" - integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== - dependencies: - "@webassemblyjs/helper-module-context" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/wast-parser" "1.7.11" - -"@webassemblyjs/floating-point-hex-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" - integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== - -"@webassemblyjs/helper-api-error@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" - integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== - -"@webassemblyjs/helper-buffer@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" - integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== - -"@webassemblyjs/helper-code-frame@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" - integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== - dependencies: - "@webassemblyjs/wast-printer" "1.7.11" - -"@webassemblyjs/helper-fsm@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" - integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== - -"@webassemblyjs/helper-module-context@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" - integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== - -"@webassemblyjs/helper-wasm-bytecode@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" - integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== - -"@webassemblyjs/helper-wasm-section@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" - integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - -"@webassemblyjs/ieee754@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" - integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" - integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== - dependencies: - "@xtuc/long" "4.2.1" - -"@webassemblyjs/utf8@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" - integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== - -"@webassemblyjs/wasm-edit@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" - integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/helper-wasm-section" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - "@webassemblyjs/wasm-opt" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - "@webassemblyjs/wast-printer" "1.7.11" - -"@webassemblyjs/wasm-gen@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" - integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/ieee754" "1.7.11" - "@webassemblyjs/leb128" "1.7.11" - "@webassemblyjs/utf8" "1.7.11" - -"@webassemblyjs/wasm-opt@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" - integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-buffer" "1.7.11" - "@webassemblyjs/wasm-gen" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - -"@webassemblyjs/wasm-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" - integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-api-error" "1.7.11" - "@webassemblyjs/helper-wasm-bytecode" "1.7.11" - "@webassemblyjs/ieee754" "1.7.11" - "@webassemblyjs/leb128" "1.7.11" - "@webassemblyjs/utf8" "1.7.11" - -"@webassemblyjs/wast-parser@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" - integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/floating-point-hex-parser" "1.7.11" - "@webassemblyjs/helper-api-error" "1.7.11" - "@webassemblyjs/helper-code-frame" "1.7.11" - "@webassemblyjs/helper-fsm" "1.7.11" - "@xtuc/long" "4.2.1" - -"@webassemblyjs/wast-printer@1.7.11": - version "1.7.11" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" - integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/wast-parser" "1.7.11" - "@xtuc/long" "4.2.1" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.1": - version "4.2.1" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" - integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - -acorn-dynamic-import@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" - integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== - dependencies: - acorn "^5.0.0" - -acorn-jsx@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" - integrity sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw== - dependencies: - acorn "^5.0.3" - -acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" - integrity sha512-cJrKCNcr2kv8dlDnbw+JPUGjHZzo4myaxOLmpOX8a+rgX94YeTcTMv/LFJUSByRpc+i4GgVnnhLxvMu/2Y+rqw== - -ajv-errors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" - integrity sha1-7PAh+hCP0X37Xms4Py3SM+Mf/Fk= - -ajv-keywords@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" - integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= - -ajv@^6.1.0, ajv@^6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" - integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -aproba@^1.0.3, aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.0.1, arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -arrify@^1.0.0, arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -assert@^1.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= - dependencies: - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= - -atob@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autoprefixer@^9.0.0: - version "9.1.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.5.tgz#8675fd8d1c0d43069f3b19a2c316f3524e4f6671" - integrity sha512-kk4Zb6RUc58ld7gdosERHMF3DzIYJc2fp5sX46qEsGXQQy5bXsu8qyLjoxuY1NuQ/cJuCYnx99BfjwnRggrYIw== - dependencies: - browserslist "^4.1.0" - caniuse-lite "^1.0.30000884" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.2" - postcss-value-parser "^3.2.3" - -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-loader@^8.0.4: - version "8.0.4" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.4.tgz#7bbf20cbe4560629e2e41534147692d3fecbdce6" - integrity sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw== - dependencies: - find-cache-dir "^1.0.0" - loader-utils "^1.0.2" - mkdirp "^0.5.1" - util.promisify "^1.0.0" - -bail@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.3.tgz#63cfb9ddbac829b02a3128cd53224be78e6c21a3" - integrity sha512-1X8CnjFVQ+a+KW36uBNMTU5s8+v5FzeqrP7hTG5aTb4aPreSbZJlhwPon9VKMuEVgV++JM+SQrALY3kr7eswdg== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU= - -bluebird@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" - integrity sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -braces@^2.3.0, braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.1.1.tgz#328eb4ff1215b12df6589e9ab82f8adaa4fc8cd6" - integrity sha512-VBorw+tgpOtZ1BYhrVSVTzTt/3+vSE3eFUh0N2GCFK1HffceOaf32YS/bs6WiFhjDAblAFrx85jMy3BG9fBK2Q== - dependencies: - caniuse-lite "^1.0.30000884" - electron-to-chromium "^1.3.62" - node-releases "^1.0.0-alpha.11" - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.1" - resolved "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -cacache@^10.0.4: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cacache@^11.0.2: - version "11.3.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.1.tgz#d09d25f6c4aca7a6d305d141ae332613aa1d515f" - integrity sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA== - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - figgy-pudding "^3.1.0" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.3" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^6.0.0" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0: - version "1.0.30000886" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000886.tgz#2127186c4f57da10d3ba26fc3e87dce4a5ddd3ae" - integrity sha512-xpYuY7rqc5+4q1n/l1BfSgIndaNqvXWKZ0Vk0ZXzVncCAkn0+huvIIPwcSL5YRJoW4MSRsgyNbjnKuh45GmknA== - -caniuse-lite@^1.0.30000884: - version "1.0.30000885" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000885.tgz#e889e9f8e7e50e769f2a49634c932b8aee622984" - integrity sha512-cXKbYwpxBLd7qHyej16JazPoUacqoVuDhvR61U7Fr5vSxMUiodzcYa1rQYRYfZ5GexV03vGZHd722vNPLjPJGQ== - -ccount@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff" - integrity sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw== - -chalk@^1.1.3: - version "1.1.3" - resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -character-entities-html4@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610" - integrity sha512-sIrXwyna2+5b0eB9W149izTPJk/KkJTg6mEzDGibwBUkyH1SbDa+nf515Ppdi3MaH35lW0JFJDWeq9Luzes1Iw== - -character-entities-legacy@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.2.tgz#7c6defb81648498222c9855309953d05f4d63a9c" - integrity sha512-9NB2VbXtXYWdXzqrvAHykE/f0QJxzaKIpZ5QzNZrrgQ7Iyxr2vnfS8fCBNVW9nUEZE0lo57nxKRqnzY/dKrwlA== - -character-entities@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.2.tgz#58c8f371c0774ef0ba9b2aca5f00d8f100e6e363" - integrity sha512-sMoHX6/nBiy3KKfC78dnEalnpn0Az0oSNvqUWYTtYrhRI5iUIYsROU48G+E+kMFQzqXaJ8kHJZ85n7y6/PHgwQ== - -character-reference-invalid@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz#21e421ad3d84055952dab4a43a04e73cd425d3ed" - integrity sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ== - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -chokidar@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" - integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" - glob-parent "^3.1.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - lodash.debounce "^4.0.8" - normalize-path "^2.1.1" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.5" - optionalDependencies: - fsevents "^1.2.2" - -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= - -chrome-trace-event@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" - integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== - dependencies: - tslib "^1.9.0" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -classlist.js@^1.1.20150312: - version "1.1.20150312" - resolved "https://registry.yarnpkg.com/classlist.js/-/classlist.js-1.1.20150312.tgz#1d70842f7022f08d9ac086ce69e5b250f2c57789" - integrity sha1-HXCEL3Ai8I2awIbOaeWyUPLFd4k= - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= - -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -clone-regexp@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f" - integrity sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw== - dependencies: - is-regexp "^1.0.0" - is-supported-regexp-flag "^1.0.0" - -coa@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.1.tgz#f3f8b0b15073e35d70263fb1042cb2c023db38af" - integrity sha512-5wfTTO8E2/ja4jFSxePXlG5nRu5bBtL/r1HCIpJW/lzT6yDtKl0u0Z4o/Vpz32IpKmBn7HerheEZQgA9N2DarQ== - dependencies: - q "^1.1.2" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= - -collapse-white-space@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.4.tgz#ce05cf49e54c3277ae573036a26851ba430a0091" - integrity sha512-YfQ1tAUZm561vpYD+5eyWN8+UsceQbSrqqlc/6zDY2gtAE+uZLSdkkovhnGpmCThsvKBFakq4EdY/FF93E8XIw== - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" - integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -colors@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= - -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== - -commander@~2.17.1: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -convert-source-map@^1.1.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== - dependencies: - safe-buffer "~5.1.1" - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js@^2.5.7: - version "2.5.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" - integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" - integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== - dependencies: - is-directory "^0.3.1" - js-yaml "^3.9.0" - parse-json "^4.0.0" - require-from-string "^2.0.1" - -cosmiconfig@^5.0.0: - version "5.0.6" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39" - integrity sha512-6DWfizHriCrFWURP1/qyhsiFvYdlJzbCzmtFWh744+KyWsJo5+kPzUZZaMRSSItoYc0pxFX7gEO7ZC1/gN/7AQ== - dependencies: - is-directory "^0.3.1" - js-yaml "^3.9.0" - parse-json "^4.0.0" - -create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-3.0.1.tgz#d0e3056b0fd88dc1ea9dceff435adbe9c702a7f8" - integrity sha512-jH4024SHZ3e0M7ann9VxpFpH3moplRXNz9ZBqvFMZqi09Yo5ARbs2wdPH8GqN9iRTlQynrbGbraNbBxBLei85Q== - dependencies: - postcss "^6.0.0" - timsort "^0.3.0" - -css-loader@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe" - integrity sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw== - dependencies: - babel-code-frame "^6.26.0" - css-selector-tokenizer "^0.7.0" - icss-utils "^2.1.0" - loader-utils "^1.0.2" - lodash "^4.17.11" - postcss "^6.0.23" - postcss-modules-extract-imports "^1.2.0" - postcss-modules-local-by-default "^1.2.0" - postcss-modules-scope "^1.1.0" - postcss-modules-values "^1.3.0" - postcss-value-parser "^3.3.0" - source-list-map "^2.0.0" - -css-select-base-adapter@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" - integrity sha1-AQKz0UYw34bD65+p9UVicBBs+ZA= - -css-select@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.0.0.tgz#7aa2921392114831f68db175c0b6a555df74bbd5" - integrity sha512-MGhoq1S9EyPgZIGnts8Yz5WwUOyHmPMdlqeifsYs/xFX7AAm3hY0RJe1dqVlXtYPI66Nsk39R/sa5/ree6L2qg== - dependencies: - boolbase "^1.0.0" - css-what "2.1" - domutils "^1.7.0" - nth-check "^1.0.1" - -css-selector-tokenizer@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" - integrity sha1-5piEdK6MlTR3v15+/s/OzNnPTIY= - dependencies: - cssesc "^0.1.0" - fastparse "^1.1.1" - regexpu-core "^1.0.0" - -css-tree@1.0.0-alpha.28: - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.28.tgz#8e8968190d886c9477bc8d61e96f61af3f7ffa7f" - integrity sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w== - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - -css-tree@1.0.0-alpha.29: - version "1.0.0-alpha.29" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39" - integrity sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg== - dependencies: - mdn-data "~1.1.0" - source-map "^0.5.3" - -css-unit-converter@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" - integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= - -css-url-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" - integrity sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w= - -css-what@2.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" - integrity sha1-lGfQMsOM+u+58teVASUwYvh/ob0= - -cssesc@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" - integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= - -cssnano-preset-default@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.0.tgz#c334287b4f7d49fb2d170a92f9214655788e3b6b" - integrity sha1-wzQoe099SfstFwqS+SFGVXiOO2s= - dependencies: - css-declaration-sorter "^3.0.0" - cssnano-util-raw-cache "^4.0.0" - postcss "^6.0.0" - postcss-calc "^6.0.0" - postcss-colormin "^4.0.0" - postcss-convert-values "^4.0.0" - postcss-discard-comments "^4.0.0" - postcss-discard-duplicates "^4.0.0" - postcss-discard-empty "^4.0.0" - postcss-discard-overridden "^4.0.0" - postcss-merge-longhand "^4.0.0" - postcss-merge-rules "^4.0.0" - postcss-minify-font-values "^4.0.0" - postcss-minify-gradients "^4.0.0" - postcss-minify-params "^4.0.0" - postcss-minify-selectors "^4.0.0" - postcss-normalize-charset "^4.0.0" - postcss-normalize-display-values "^4.0.0" - postcss-normalize-positions "^4.0.0" - postcss-normalize-repeat-style "^4.0.0" - postcss-normalize-string "^4.0.0" - postcss-normalize-timing-functions "^4.0.0" - postcss-normalize-unicode "^4.0.0" - postcss-normalize-url "^4.0.0" - postcss-normalize-whitespace "^4.0.0" - postcss-ordered-values "^4.0.0" - postcss-reduce-initial "^4.0.0" - postcss-reduce-transforms "^4.0.0" - postcss-svgo "^4.0.0" - postcss-unique-selectors "^4.0.0" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.0.tgz#be0a2856e25f185f5f7a2bcc0624e28b7f179a9f" - integrity sha1-vgooVuJfGF9feivMBiTii38Xmp8= - dependencies: - postcss "^6.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.0.tgz#d2a3de1039aa98bc4ec25001fa050330c2a16dac" - integrity sha1-0qPeEDmqmLxOwlAB+gUDMMKhbaw= - -cssnano@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.0.tgz#682c37b84b9b7df616450a5a8dc9269b9bd10734" - integrity sha512-7x24b/ghbrQv2QRgqMR12H3ZZ38xYCKJSXfg21YCtnIE177/NyvMkeiuQdWauIgMjySaTZ+cd5PN2qvfbsGeSw== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.0" - is-resolvable "^1.0.0" - postcss "^6.0.0" - -csso@^3.5.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b" - integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg== - dependencies: - css-tree "1.0.0-alpha.29" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - -cyclist@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" - integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= - -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= - -debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^4.0.0, debug@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.0.1.tgz#f9bb36d439b8d1f0dd52d8fb6b46e4ebb8c1cd5b" - integrity sha512-K23FHJ/Mt404FSlp6gSZCevIbTMLX0j3fmHhUEhQ3Wq0FMODW3+cUSoLdy1Gx4polAf4t/lphhmHH35BB8cLYw== - dependencies: - ms "^2.1.1" - -decamelize-keys@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decamelize@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" - integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== - dependencies: - xregexp "4.0.0" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -define-properties@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" - integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== - dependencies: - arrify "^1.0.1" - path-type "^3.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - integrity sha1-BzxpdUbOB4DOI75KKOKT5AvDDII= - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - integrity sha1-sXrtguirWeUt2cGbF1bg/BhyBMI= - -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs= - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -dot-prop@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" - integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== - dependencies: - is-obj "^1.0.0" - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410" - integrity sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -electron-to-chromium@^1.3.62: - version "1.3.63" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.63.tgz#6485f5f4f3375358aa8fa23c2029ada208483b8d" - integrity sha512-Ec35NNY040HKuSxMAzBMgz/uUI78amSWpBUD9x2gN7R7gkb/wgAcClngWklcLP0/lm/g0UUYHnC/tUIlZj8UvQ== - -element-closest@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-2.0.2.tgz#72a740a107453382e28df9ce5dbb5a8df0f966ec" - integrity sha1-cqdAoQdFM4LijfnOXbtajfD5Zuw= - -elliptic@^6.0.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" - integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" - integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.4.0" - tapable "^1.0.0" - -entities@^1.1.1, entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= - -errno@^0.1.3, errno@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.5.1, es-abstract@^1.6.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" - integrity sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA== - dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" - -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - integrity sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0= - dependencies: - is-callable "^1.1.1" - is-date-object "^1.0.1" - is-symbol "^1.0.1" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-loader@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.1.tgz#2a9251523652430bfdd643efdb0afc1a2a89546a" - integrity sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ== - dependencies: - loader-fs-cache "^1.0.0" - loader-utils "^1.0.2" - object-assign "^4.0.1" - object-hash "^1.1.4" - rimraf "^2.6.1" - -eslint-plugin-only-ascii@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-only-ascii/-/eslint-plugin-only-ascii-0.0.0.tgz#452dd8d79a086b385160735d895cb4ce4332ed65" - integrity sha1-RS3Y15oIazhRYHNdiVy0zkMy7WU= - dependencies: - requireindex "~1.1.0" - -eslint-scope@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" - integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" - integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== - -eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== - -eslint@^5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.8.0.tgz#91fbf24f6e0471e8fdf681a4d9dd1b2c9f28309b" - integrity sha512-Zok6Bru3y2JprqTNm14mgQ15YQu/SMDkWdnmHfFg770DIUlmMFd/gqqzCHekxzjHZJxXv3tmTpH0C1icaYJsRQ== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.5.3" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^2.1.0" - eslint-scope "^4.0.0" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^4.0.0" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - imurmurhash "^0.1.4" - inquirer "^6.1.0" - is-resolvable "^1.1.0" - js-yaml "^3.12.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.5" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - regexpp "^2.0.1" - require-uncached "^1.0.3" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.0.2" - text-table "^0.2.0" - -espree@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" - integrity sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg== - dependencies: - acorn "^5.6.0" - acorn-jsx "^4.1.1" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== - dependencies: - estraverse "^4.0.0" - -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== - dependencies: - estraverse "^4.1.0" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - -events@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= - -evil-icons@^1.10.1: - version "1.10.1" - resolved "https://registry.yarnpkg.com/evil-icons/-/evil-icons-1.10.1.tgz#5c6abfec541025a90f73bba6151340e015ef7f9b" - integrity sha512-gIBzN6rpvG5om/WAu1rEiE9SgT9mQ00cmYvRb6Cr4ngVaz9Ae8JGeEByMOvrfKvrMhsZzLCNmUJLBJZwjri4bw== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" - integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== - dependencies: - cross-spawn "^6.0.0" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execall@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73" - integrity sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M= - dependencies: - clone-regexp "^1.0.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - -expand-tilde@^2.0.0, expand-tilde@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" - integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= - dependencies: - homedir-polyfill "^1.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-glob@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.2.tgz#71723338ac9b4e0e2fff1d6748a2a13d5ed352bf" - integrity sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.0.1" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.1" - micromatch "^3.1.10" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastparse@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" - integrity sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg= - -figgy-pudding@^3.1.0, figgy-pudding@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" - integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -file-loader@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-2.0.0.tgz#39749c82f020b9e85901dcff98e8004e6401cfde" - integrity sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ== - dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" - integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= - dependencies: - commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" - -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" - -find-cache-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" - integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA== - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^3.0.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - integrity sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE= - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - -flatten@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" - integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= - -flush-write-stream@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" - integrity sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw== - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.4" - -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - -formdata-polyfill@^3.0.12: - version "3.0.12" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.12.tgz#43f8d9bad5408a57c4f801784526e8230b6e9f7a" - integrity sha512-y5V1Y4e2VSJ29+CAHozJwN9BqvsigYicZp/MqeYP00X/UMah3cLb2ix7/58fLcaAjwr8HfztD7Ih/IQCW1BGfw== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-minipass@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== - dependencies: - minipass "^2.2.1" - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" - -function-bind@^1.1.0, function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== - -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -global-modules-path@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.3.0.tgz#b0e2bac6beac39745f7db5c59d26a36a0b94f7dc" - integrity sha512-HchvMJNYh9dGSCy8pOQ2O8u/hoXaL+0XhnrwH0RyLiSXMMTl9W3N6KUU73+JFOg5PGjtzl6VZzUQsnrpm7Szag== - -global-modules@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" - integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== - dependencies: - global-prefix "^1.0.1" - is-windows "^1.0.1" - resolve-dir "^1.0.0" - -global-prefix@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" - integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= - dependencies: - expand-tilde "^2.0.2" - homedir-polyfill "^1.0.1" - ini "^1.3.4" - is-windows "^1.0.1" - which "^1.2.14" - -globals@^11.1.0, globals@^11.7.0: - version "11.7.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" - integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg== - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^8.0.0, globby@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50" - integrity sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw== - dependencies: - array-union "^1.0.1" - dir-glob "^2.0.0" - fast-glob "^2.0.2" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" - -globjoin@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= - -gonzales-pe@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2" - integrity sha512-Kjhohco0esHQnOiqqdJeNz/5fyPkOMD/d6XVjwTAoPGUFh0mCollPUTUTa2OZy4dYNAqlPIQdTiNzJTWdd9Htw== - dependencies: - minimist "1.1.x" - -graceful-fs@^4.1.11, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" - integrity sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= - dependencies: - parse-passwd "^1.0.0" - -hosted-git-info@^2.1.4: - version "2.7.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-comment-regex@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" - integrity sha1-ZouTd26q5V696POtRkswekljYl4= - -html-tags@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" - integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= - -htmlparser2@^3.9.2: - version "3.9.2" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" - integrity sha1-G9+HrMoPP55T+k/M6w9LTLsAszg= - dependencies: - domelementtype "^1.3.0" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^2.0.2" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -iconv-lite@^0.4.24, iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" - integrity sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI= - dependencies: - postcss "^6.0.1" - -ieee754@^1.1.4: - version "1.1.12" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== - dependencies: - minimatch "^3.0.4" - -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.0, ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-lazy@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" - integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== - -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -ini@^1.3.4, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - -inquirer@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" - integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.0" - figures "^2.0.0" - lodash "^4.17.10" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.1.0" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -interpret@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= - -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-alphabetical@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.2.tgz#1fa6e49213cb7885b75d15862fb3f3d96c884f41" - integrity sha512-V0xN4BYezDHcBSKb1QHUFMlR4as/XEuCZBzMJUU4n7+Cbt33SmUnSol+pnXFvLxSHNq2CemUXNdaXV6Flg7+xg== - -is-alphanumeric@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" - integrity sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ= - -is-alphanumerical@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz#1138e9ae5040158dc6ff76b820acd6b7a181fd40" - integrity sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.4, is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= - dependencies: - builtin-modules "^1.0.0" - -is-callable@^1.1.1, is-callable@^1.1.3: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - -is-decimal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.2.tgz#894662d6a8709d307f3a276ca4339c8fa5dff0ff" - integrity sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg== - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= - dependencies: - is-extglob "^2.1.1" - -is-hexadecimal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz#b6e710d7d07bb66b98cb8cece5c9b4921deeb835" - integrity sha512-but/G3sapV3MNyqiDBLrOi4x8uCIw0RY3o/Vb5GT0sMFHrVV7731wFSVy41T5FO1og7G0gXLJh0MkgPRouko/A== - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= - -is-path-in-cwd@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= - -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - -is-resolvable@^1.0.0, is-resolvable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-supported-regexp-flag@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz#21ee16518d2c1dd3edd3e9a0d57e50207ac364ca" - integrity sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ== - -is-svg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" - integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== - dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - integrity sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI= - -is-whitespace-character@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed" - integrity sha512-SzM+T5GKUCtLhlHFKt2SDAX2RFzfS6joT91F2/WSi9LxgFdsnhfPK/UIA+JhRR2xuyLdrCys2PiFDrtn1fU5hQ== - -is-windows@^1.0.1, is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-word-character@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.2.tgz#46a5dac3f2a1840898b91e576cd40d493f3ae553" - integrity sha512-T3FlsX8rCHAH8e7RE7PfOPZVFQlcV3XRF9eOOBQ1uf70OxO7CjjSOjeImMPCADBdYWcStAbVbYvJ1m2D3tb+EA== - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -js-levenshtein@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.3.tgz#3ef627df48ec8cf24bacf05c0f184ff30ef413c5" - integrity sha512-/812MXr9RBtMObviZ8gQBhHO8MOrGj8HlEE+4ccMTElNA/6I3u39u+bhny55Lk921yn44nSZFy9naNLElL5wgQ== - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-yaml@^3.12.0, js-yaml@^3.9.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" - integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsesc@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" - integrity sha1-5CGiqOINawgZ3yiQj3glJrlt0f4= - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== - -known-css-properties@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.9.0.tgz#28f8a7134cfa3b0aa08b1e5edf64a57f64fc23af" - integrity sha512-2G/A/8XPhH6MmuVgl079wYsgdqfXE3cfm62txk/ajS4wvRWo6tEHcgQCJCHOOy12Fse1Sxlbf7/IJBpR9hnVew== - -last-call-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" - integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== - dependencies: - lodash "^4.17.5" - webpack-sources "^1.1.0" - -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - -leven@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -loader-fs-cache@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" - integrity sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw= - dependencies: - find-cache-dir "^0.1.1" - mkdirp "0.5.1" - -loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" - integrity sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI= - -loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== - -lodash@^4.17.11: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== - -log-symbols@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -longest-streak@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e" - integrity sha512-TmYTeEYxiAmSVdpbnQDXGtvYOIRsCMg89CVZzwzc2o7GFL1CjoiRPjH5ec0NFAVlAx3fVof9dX/t6KKRAo2OWA== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - -lru-cache@^4.1.1, lru-cache@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -map-age-cleaner@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74" - integrity sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ== - dependencies: - p-defer "^1.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -markdown-escapes@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.2.tgz#e639cbde7b99c841c0bacc8a07982873b46d2122" - integrity sha512-lbRZ2mE3Q9RtLjxZBZ9+IMl68DKIXaVAhwvwn9pmjnPLS0h/6kyBMgNhqi1xFJ/2yv6cSyv0jbiZavZv93JkkA== - -markdown-table@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.2.tgz#c78db948fa879903a41bce522e3b96f801c63786" - integrity sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw== - -math-random@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" - integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= - -mathml-tag-names@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.0.tgz#490b70e062ee24636536e3d9481e333733d00f2c" - integrity sha512-3Zs9P/0zzwTob2pdgT0CHZuMbnSUSp8MB1bddfm+HDmnFWHGT4jvEZRf+2RuPoa+cjdn/z25SEt5gFTqdhvJAg== - -md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - integrity sha1-6b296UogpawYsENA/Fdk1bCdkB0= - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -mdast-util-compact@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.2.tgz#c12ebe16fffc84573d3e19767726de226e95f649" - integrity sha512-d2WS98JSDVbpSsBfVvD9TaDMlqPRz7ohM/11G0rp5jOBb5q96RJ6YLszQ/09AAixyzh23FeIpCGqfaamEADtWg== - dependencies: - unist-util-visit "^1.1.0" - -mdn-data@~1.1.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01" - integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA== - -mem@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" - integrity sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA== - dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^1.0.0" - p-is-promise "^1.1.0" - -memory-fs@^0.4.0, memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - -merge2@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.2.tgz#03212e3da8d86c4d8523cebd6318193414f94e34" - integrity sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg== - -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime@^2.0.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" - integrity sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mini-css-extract-plugin@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" - integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== - dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - -minimist@0.0.8: - version "0.0.8" - resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@1.1.x: - version "1.1.3" - resolved "http://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" - integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= - -minimist@^1.2.0: - version "1.2.0" - resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minipass@^2.2.1, minipass@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" - integrity sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" - integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA== - dependencies: - minipass "^2.2.1" - -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^2.0.1" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: - version "0.5.1" - resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -nan@^2.9.2: - version "2.11.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" - integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -needle@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.2.tgz#1120ca4c41f2fcc6976fd28a8968afe239929418" - integrity sha512-mW7W8dKuVYefCpNzE3Z7xUmPI9wSrSL/1qH31YGMxmSOAnjatS3S9Zv3cmiHrhx3Jkp1SrWWBdOFXjfF48Uq3A== - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - -neo-async@^2.5.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc" - integrity sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-libs-browser@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" - integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^1.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.0" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.10.3" - vm-browserify "0.0.4" - -node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^1.0.0-alpha.11: - version "1.0.0-alpha.11" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.0-alpha.11.tgz#73c810acc2e5b741a17ddfbb39dfca9ab9359d8a" - integrity sha512-CaViu+2FqTNYOYNihXa5uPS/zry92I3vPU4nCB6JB3OeZ2UGtOpF5gRwuN4+m3hbEcL47bOXyun1jX2iC+3uEQ== - dependencies: - semver "^5.3.0" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^2.0.1, normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-selector@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" - integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -npm-bundled@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" - integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== - -npm-packlist@^1.1.6: - version "1.1.11" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" - integrity sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -nth-check@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" - integrity sha1-mSms32KPwsQQmN6rgqxYDPFJquQ= - dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-hash@^1.1.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.0.tgz#76d9ba6ff113cf8efc0d996102851fe6723963e2" - integrity sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ== - -object-keys@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" - integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" - integrity sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.6.1" - function-bind "^1.1.0" - has "^1.0.1" - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -optimize-css-assets-webpack-plugin@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz#9eb500711d35165b45e7fd60ba2df40cb3eb9159" - integrity sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A== - dependencies: - cssnano "^4.1.0" - last-call-webpack-plugin "^3.0.0" - -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - -os-locale@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620" - integrity sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw== - dependencies: - execa "^0.10.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" - integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" - integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== - -pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg== - -parallel-transform@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" - integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= - dependencies: - cyclist "~0.2.2" - inherits "^2.0.3" - readable-stream "^2.1.5" - -parse-asn1@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" - integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - -parse-entities@^1.0.2, parse-entities@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.1.2.tgz#9eaf719b29dc3bd62246b4332009072e01527777" - integrity sha512-5N9lmQ7tmxfXf+hO3X6KRG6w7uYO/HL9fHalSySTdyn63C3WNvTM/1R8tn1u1larNcEbo3Slcy2bsVDQqvEpUg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" - integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.1, path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -pbkdf2@^3.0.3: - version "3.0.16" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" - integrity sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.0.tgz#db04c982b632fd0df9090d14aaf1c8413cadb695" - integrity sha512-zrSP/KDf9DH3K3VePONoCstgPiYJy9z0SCatZuTpOc7YdnWIqwkWdXOuwlr4uDc7em8QZRsFWsT/685x5InjYg== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= - dependencies: - find-up "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" - integrity sha1-PSQXG79udinUIqQ26/5t2VEfQzA= - dependencies: - css-unit-converter "^1.1.1" - postcss "^6.0.0" - postcss-selector-parser "^2.2.2" - reduce-css-calc "^2.0.0" - -postcss-colormin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.1.tgz#6f1c18a0155bc69613f2ff13843e2e4ae8ff0bbe" - integrity sha1-bxwYoBVbxpYT8v8ThD4uSuj/C74= - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.0.tgz#77d77d9aed1dc4e6956e651cc349d53305876f62" - integrity sha1-d9d9mu0dxOaVbmUcw0nVMwWHb2I= - dependencies: - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-discard-comments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.0.tgz#9684a299e76b3e93263ef8fd2adbf1a1c08fd88d" - integrity sha1-loSimedrPpMmPvj9KtvxocCP2I0= - dependencies: - postcss "^6.0.0" - -postcss-discard-duplicates@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.0.tgz#42f3c267f85fa909e042c35767ecfd65cb2bd72c" - integrity sha1-QvPCZ/hfqQngQsNXZ+z9Zcsr1yw= - dependencies: - postcss "^6.0.0" - -postcss-discard-empty@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.0.tgz#55e18a59c74128e38c7d2804bcfa4056611fb97f" - integrity sha1-VeGKWcdBKOOMfSgEvPpAVmEfuX8= - dependencies: - postcss "^6.0.0" - -postcss-discard-overridden@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.0.tgz#4a0bf85978784cf1f81ed2c1c1fd9d964a1da1fa" - integrity sha1-Sgv4WXh4TPH4HtLBwf2dlkodofo= - dependencies: - postcss "^6.0.0" - -postcss-html@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.34.0.tgz#9bfd637ad8c3d3a43625b5ef844dc804b3370868" - integrity sha512-BIW982Kbf9/RikInNhNS3/GA6x/qY/+jhVS9KumqXZtU9ss8Yq15HhPJ6mnaXcU5bFq2ULxpOv96mHPAErpGMQ== - dependencies: - htmlparser2 "^3.9.2" - -postcss-jsx@^0.35.0: - version "0.35.0" - resolved "https://registry.yarnpkg.com/postcss-jsx/-/postcss-jsx-0.35.0.tgz#1d6cb82393994cdc7e9aa421648e3f0f3f98209b" - integrity sha512-AU2/9QDmHYJRxTiniMt2bJ9fwCzVF6n00VnR4gdnFGHeXRW2mGwoptpuPgYjfivkdI8LlNIuo+w8TyS6a4JhJw== - dependencies: - "@babel/core" "^7.1.2" - optionalDependencies: - postcss-styled ">=0.34.0" - -postcss-less@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.0.2.tgz#9cf94e2cc90f8566858939e278fb9f0b713908df" - integrity sha512-+JBOampmDnuaf4w8OIEqkCiF+sOm/nWukDsC+1FTrYcIstptOISzGpYZk24Qh+Ewlmzmi53sRyiTbiGvMCDRwA== - dependencies: - postcss "^7.0.3" - -postcss-load-config@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" - integrity sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ== - dependencies: - cosmiconfig "^4.0.0" - import-cwd "^2.0.0" - -postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - -postcss-markdown@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.34.0.tgz#7a043e6eee3ab846a4cefe3ab43d141038e2da79" - integrity sha512-cKPggF9OMOKPoqDm5YpYszCqMsImFh78FK6P8p6IsEKZB6IkUJYKz0/QgadYy4jLb60jcFIHJ6v6jsMH7/ZQrA== - dependencies: - remark "^9.0.0" - unist-util-find-all-after "^1.0.2" - -postcss-media-query-parser@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= - -postcss-merge-longhand@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.5.tgz#00898d72347fc7e40bb564b11bdc08119c599b59" - integrity sha512-tw2obF6I2VhXhPMObQc1QpQO850m3arhqP3PcBAU7Tx70v73QF6brs9uK0XKMNuC7BPo6DW+fh07cGhrLL57HA== - dependencies: - css-color-names "0.0.4" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.1.tgz#430fd59b3f2ed2e8afcd0b31278eda39854abb10" - integrity sha1-Qw/Vmz8u0uivzQsxJ47aOYVKuxA= - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^6.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.0.tgz#4cc33d283d6a81759036e757ef981d92cbd85bed" - integrity sha1-TMM9KD1qgXWQNudX75gdksvYW+0= - dependencies: - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.0.tgz#3fc3916439d27a9bb8066db7cdad801650eb090e" - integrity sha1-P8ORZDnSepu4Bm23za2AFlDrCQ4= - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.0.tgz#05e9166ee48c05af651989ce84d39c1b4d790674" - integrity sha1-BekWbuSMBa9lGYnOhNOcG015BnQ= - dependencies: - alphanum-sort "^1.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.0.tgz#b1e9f6c463416d3fcdcb26e7b785d95f61578aad" - integrity sha1-sen2xGNBbT/Nyybnt4XZX2FXiq0= - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^6.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" - integrity sha1-ZhQOzs447wa/DT41XWm/WdFB6oU= - dependencies: - postcss "^6.0.1" - -postcss-modules-local-by-default@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-values@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" - integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^6.0.1" - -postcss-normalize-charset@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.0.tgz#24527292702d5e8129eafa3d1de49ed51a6ab730" - integrity sha1-JFJyknAtXoEp6vo9HeSe1RpqtzA= - dependencies: - postcss "^6.0.0" - -postcss-normalize-display-values@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.0.tgz#950e0c7be3445770a160fffd6b6644c3c0cd8f89" - integrity sha1-lQ4Me+NEV3ChYP/9a2ZEw8DNj4k= - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.0.tgz#ee9343ab981b822c63ab72615ecccd08564445a3" - integrity sha1-7pNDq5gbgixjq3JhXszNCFZERaM= - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.0.tgz#b711c592cf16faf9ff575e42fa100b6799083eff" - integrity sha1-txHFks8W+vn/V15C+hALZ5kIPv8= - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.0.tgz#718cb6d30a6fac6ac6a830e32c06c07dbc66fe5d" - integrity sha1-cYy20wpvrGrGqDDjLAbAfbxm/l0= - dependencies: - has "^1.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.0.tgz#0351f29886aa981d43d91b2c2bd1aea6d0af6d23" - integrity sha1-A1HymIaqmB1D2RssK9GuptCvbSM= - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.0.tgz#5acd5d47baea5d17674b2ccc4ae5166fa88cdf97" - integrity sha1-Ws1dR7rqXRdnSyzMSuUWb6iM35c= - dependencies: - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.0.tgz#b7a9c8ad26cf26694c146eb2d68bd0cf49956f0d" - integrity sha1-t6nIrSbPJmlMFG6y1ovQz0mVbw0= - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.0.tgz#1da7e76b10ae63c11827fa04fc3bb4a1efe99cc0" - integrity sha1-HafnaxCuY8EYJ/oE/Du0oe/pnMA= - dependencies: - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.0.tgz#2c769d5d44aa3c7c907b8be2e997ed19dfd8d50a" - integrity sha512-gbqbEiONKKJgoOKhtzBjFqmHSzviPL4rv0ACVcFS7wxWXBY07agFXRQ7Y3eMGV0ZORzQXp2NGnj0c+imJG0NcA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-initial@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.1.tgz#f2d58f50cea2b0c5dc1278d6ea5ed0ff5829c293" - integrity sha1-8tWPUM6isMXcEnjW6l7Q/1gpwpM= - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^6.0.0" - -postcss-reduce-transforms@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.0.tgz#f645fc7440c35274f40de8104e14ad7163edf188" - integrity sha1-9kX8dEDDUnT0DegQThStcWPt8Yg= - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - -postcss-reporter@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-6.0.0.tgz#44c873129d8c029a430b6d2186210d79c8de88b8" - integrity sha512-5xQXm1UPWuFObjbtyQzWvQaupru8yFcFi4HUlm6OPo1o2bUszYASuqRJ7bVArb3svGCdbYtqdMBKrqR1Aoy+tw== - dependencies: - chalk "^2.0.1" - lodash "^4.17.4" - log-symbols "^2.0.0" - postcss "^7.0.2" - -postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= - -postcss-safe-parser@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz#8756d9e4c36fdce2c72b091bbc8ca176ab1fcdea" - integrity sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ== - dependencies: - postcss "^7.0.0" - -postcss-sass@^0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.3.tgz#bec188ac285d21ac8feba194c2f327fdda31e671" - integrity sha512-uoRhfwZJHDRI8p2KQniTx4UwzYwKgQUhmFNJ7aysL3+tgFUfmv5TPX8UPnlE5gfrq6KHUUwPJ/nISFtzwxr7iQ== - dependencies: - gonzales-pe "^4.2.3" - postcss "^7.0.1" - -postcss-scss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1" - integrity sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug== - dependencies: - postcss "^7.0.0" - -postcss-selector-parser@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" - integrity sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A= - dependencies: - flatten "^1.0.2" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" - integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= - dependencies: - dot-prop "^4.1.1" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-styled@>=0.34.0, postcss-styled@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/postcss-styled/-/postcss-styled-0.34.0.tgz#07d47bcb13707289782aa058605fd9feaf84391d" - integrity sha512-Uaeetr/xOiQWGJgzPFOr32/Bwykpfh9TVE26OpmwDb8eEN205TS/gqkt9ri+C6otQzQKXqbMfeZNbKYi7QpeNA== - -postcss-svgo@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.0.tgz#c0bbad02520fc636c9d78b0e8403e2e515c32285" - integrity sha1-wLutAlIPxjbJ14sOhAPi5RXDIoU= - dependencies: - is-svg "^3.0.0" - postcss "^6.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-syntax@^0.34.0: - version "0.34.0" - resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.34.0.tgz#4a85c022f1cdecea72102775c91af1e7f506d83a" - integrity sha512-L36NZwq2UK743US+vl1CRMdBRZCBmFYfThP9n9jCFhX1Wfk6BqnRSgt0Fy8q44IwxPee/GCzlo7T1c1JIeUDlQ== - -postcss-unique-selectors@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.0.tgz#04c1e9764c75874261303402c41f0e9769fc5501" - integrity sha1-BMHpdkx1h0JhMDQCxB8Ol2n8VQE= - dependencies: - alphanum-sort "^1.0.0" - postcss "^6.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" - integrity sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU= - -postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.23: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.2.tgz#7b5a109de356804e27f95a960bef0e4d5bc9bb18" - integrity sha512-fmaUY5370keLUTx+CnwRxtGiuFTcNBLQBqr1oE3WZ/euIYmGAo0OAgOhVJ3ByDnVmOR3PK+0V9VebzfjRIUcqw== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.3: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55" - integrity sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.5.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - -private@^0.1.6: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -public-encrypt@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" - integrity sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - -pump@^2.0.0, pump@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - -ramda@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" - integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== - -randomatic@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.0.tgz#36f2ca708e9e567f5ed2ec01949026d50aa10116" - integrity sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" - integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -raw-loader@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" - integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg= - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - -reduce-css-calc@^2.0.0: - version "2.1.5" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.5.tgz#f283712f0c9708ef952d328f4b16112d57b03714" - integrity sha512-AybiBU03FKbjYzyvJvwkJZY6NLN+80Ufc2EqEs+41yQH+8wqBEslD6eGiS0oIeq5TNLA5PrhBeYHXWdn8gtW7A== - dependencies: - css-unit-converter "^1.1.1" - postcss-value-parser "^3.3.0" - -regenerate-unicode-properties@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" - integrity sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.2.1, regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-runtime@^0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -regenerator-transform@^0.13.3: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" - integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA== - dependencies: - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpu-core@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" - integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - -regexpu-core@^4.1.3, regexpu-core@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d" - integrity sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^7.0.0" - regjsgen "^0.4.0" - regjsparser "^0.3.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.0.2" - -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= - -regjsgen@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" - integrity sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA== - -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= - dependencies: - jsesc "~0.5.0" - -regjsparser@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" - integrity sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA== - dependencies: - jsesc "~0.5.0" - -remark-parse@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" - integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== - dependencies: - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^1.1.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^1.0.0" - vfile-location "^2.0.0" - xtend "^4.0.1" - -remark-stringify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-5.0.0.tgz#336d3a4d4a6a3390d933eeba62e8de4bd280afba" - integrity sha512-Ws5MdA69ftqQ/yhRF9XhVV29mhxbfGhbz0Rx5bQH+oJcNhhSM6nCu1EpLod+DjrFGrU0BMPs+czVmJZU7xiS7w== - dependencies: - ccount "^1.0.0" - is-alphanumeric "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - longest-streak "^2.0.1" - markdown-escapes "^1.0.0" - markdown-table "^1.1.0" - mdast-util-compact "^1.0.0" - parse-entities "^1.0.2" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - stringify-entities "^1.0.1" - unherit "^1.0.4" - xtend "^4.0.1" - -remark@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark/-/remark-9.0.0.tgz#c5cfa8ec535c73a67c4b0f12bfdbd3a67d8b2f60" - integrity sha512-amw8rGdD5lHbMEakiEsllmkdBP+/KpjW/PRK6NSGPZKCQowh0BT4IWXDAkRMyG3SB9dKPXWMviFjNusXzXNn3A== - dependencies: - remark-parse "^5.0.0" - remark-stringify "^5.0.0" - unified "^6.0.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -replace-ext@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-from-string@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requireindex@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162" - integrity sha1-5UBLgVV+91225JxacgBIk/4D4WI= - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-dir@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" - integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= - dependencies: - expand-tilde "^2.0.0" - global-modules "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.3.2: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== - dependencies: - path-parse "^1.0.5" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== - dependencies: - glob "^7.0.5" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rxjs@^6.1.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.2.tgz#6a688b16c4e6e980e62ea805ec30648e1c60907f" - integrity sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw== - dependencies: - tslib "^1.9.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@^1.2.4, sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -schema-utils@^0.4.4, schema-utils@^0.4.5: - version "0.4.7" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" - integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -script-loader@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/script-loader/-/script-loader-0.7.2.tgz#2016db6f86f25f5cf56da38915d83378bb166ba7" - integrity sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA== - dependencies: - raw-loader "~0.5.1" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== - -serialize-javascript@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" - integrity sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ== - -set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= - -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" - -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== - dependencies: - is-fullwidth-code-point "^2.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" - integrity sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A== - -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== - dependencies: - atob "^2.1.1" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@~0.5.6: - version "0.5.9" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" - integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - integrity sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - integrity sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg== - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== - -specificity@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" - integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -ssri@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" - integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== - dependencies: - safe-buffer "^5.1.1" - -ssri@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== - dependencies: - figgy-pudding "^3.5.1" - -stable@~0.1.6: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -state-toggle@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.1.tgz#c3cb0974f40a6a0f8e905b96789eb41afa1cde3a" - integrity sha512-Qe8QntFrrpWTnHwvwj2FZTgv+PKIsp0B9VxLzLLbSpPXWOgRgc5LVj/aTiSfK1RqIeF9jeC1UeOH8Q8y60A7og== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -stream-browserify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@^1.0.0, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -stringify-entities@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7" - integrity sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A== - dependencies: - character-entities-html4 "^1.0.0" - character-entities-legacy "^1.0.0" - is-alphanumerical "^1.0.0" - is-hexadecimal "^1.0.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -style-loader@^0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" - integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== - dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" - -style-search@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= - -stylehacks@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.0.tgz#64b323951c4a24e5fc7b2ec06c137bf32d155e8a" - integrity sha1-ZLMjlRxKJOX8ey7AbBN78y0VXoo= - dependencies: - browserslist "^4.0.0" - postcss "^6.0.0" - postcss-selector-parser "^3.0.0" - -stylelint-config-recommended@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.1.0.tgz#f526d5c771c6811186d9eaedbed02195fee30858" - integrity sha512-ajMbivOD7JxdsnlS5945KYhvt7L/HwN6YeYF2BH6kE4UCLJR0YvXMf+2j7nQpJyYLZx9uZzU5G1ZOSBiWAc6yA== - -stylelint-config-standard@^18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.2.0.tgz#6283149aba7f64f18731aef8f0abfb35cf619e06" - integrity sha512-07x0TaSIzvXlbOioUU4ORkCIM07kyIuojkbSVCyFWNVgXMXYHfhnQSCkqu+oHWJf3YADAnPGWzdJ53NxkoJ7RA== - dependencies: - stylelint-config-recommended "^2.1.0" - -stylelint-webpack-plugin@^0.10.5: - version "0.10.5" - resolved "https://registry.yarnpkg.com/stylelint-webpack-plugin/-/stylelint-webpack-plugin-0.10.5.tgz#0b6e0d373ff5e03baa8197ebe0f2625981bd266b" - integrity sha512-jtYx3aJ2qDMvBMswe5NRPTO7kJgAKafc6GilAkWDp/ewoAmnoxA6TsYMnIPtLECRLwXevaCPvlh2JEUMGZCoUQ== - dependencies: - arrify "^1.0.1" - micromatch "^3.1.8" - object-assign "^4.1.0" - ramda "^0.25.0" - -stylelint@^9.7.1: - version "9.7.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.7.1.tgz#522f8795832a9f7e062e5e4105c0e05fb53f827f" - integrity sha512-w3Xxnm2YElBmNAhmTjkTEyklAU2P+R8QMqDVM3S98zRLNPNLcCRXWzqtYsItbZYHQzSNOa6K20KxPVPfD8SFAw== - dependencies: - autoprefixer "^9.0.0" - balanced-match "^1.0.0" - chalk "^2.4.1" - cosmiconfig "^5.0.0" - debug "^4.0.0" - execall "^1.0.0" - file-entry-cache "^2.0.0" - get-stdin "^6.0.0" - global-modules "^1.0.0" - globby "^8.0.0" - globjoin "^0.1.4" - html-tags "^2.0.0" - ignore "^4.0.0" - import-lazy "^3.1.0" - imurmurhash "^0.1.4" - known-css-properties "^0.9.0" - leven "^2.1.0" - lodash "^4.17.4" - log-symbols "^2.0.0" - mathml-tag-names "^2.0.1" - meow "^5.0.0" - micromatch "^2.3.11" - normalize-selector "^0.2.0" - pify "^4.0.0" - postcss "^7.0.0" - postcss-html "^0.34.0" - postcss-jsx "^0.35.0" - postcss-less "^3.0.1" - postcss-markdown "^0.34.0" - postcss-media-query-parser "^0.2.3" - postcss-reporter "^6.0.0" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^4.0.0" - postcss-sass "^0.3.0" - postcss-scss "^2.0.0" - postcss-selector-parser "^3.1.0" - postcss-styled "^0.34.0" - postcss-syntax "^0.34.0" - postcss-value-parser "^3.3.0" - resolve-from "^4.0.0" - signal-exit "^3.0.2" - specificity "^0.4.1" - string-width "^2.1.0" - style-search "^0.1.0" - sugarss "^2.0.0" - svg-tags "^1.0.0" - table "^5.0.0" - -sugarss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" - integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== - dependencies: - postcss "^7.0.2" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -svg-tags@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= - -svgo@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.1.1.tgz#12384b03335bcecd85cfa5f4e3375fed671cb985" - integrity sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g== - dependencies: - coa "~2.0.1" - colors "~1.1.2" - css-select "^2.0.0" - css-select-base-adapter "~0.1.0" - css-tree "1.0.0-alpha.28" - css-url-regex "^1.1.0" - csso "^3.5.0" - js-yaml "^3.12.0" - mkdirp "~0.5.1" - object.values "^1.0.4" - sax "~1.2.4" - stable "~0.1.6" - unquote "~1.1.1" - util.promisify "~1.0.0" - -table@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-5.0.2.tgz#2e2fab7af041cc9f38ffcdaf6d02f732c1839dc1" - integrity sha512-erSn+OGawmDDqgmajCrh2GyzzqKE39P3abmxhqIIdTsOTIFIYl8I6JVDM8x5w+wX4sFyrT2JdP9UF/VEtW5g0Q== - dependencies: - ajv "^6.5.3" - lodash "^4.17.10" - slice-ansi "1.0.0" - string-width "^2.1.1" - -table@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" - integrity sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg== - dependencies: - ajv "^6.5.3" - lodash "^4.17.10" - slice-ansi "1.0.0" - string-width "^2.1.1" - -tapable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" - integrity sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg== - -tapable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c" - integrity sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA== - -tar@^4: - version "4.4.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" - integrity sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg== - dependencies: - chownr "^1.0.1" - fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - -terser-webpack-plugin@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz#cf7c25a1eee25bf121f4a587bb9e004e3f80e528" - integrity sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA== - dependencies: - cacache "^11.0.2" - find-cache-dir "^2.0.0" - schema-utils "^1.0.0" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - terser "^3.8.1" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -terser@^3.8.1: - version "3.10.11" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.10.11.tgz#e063da74b194dde9faf0a561f3a438c549d2da3f" - integrity sha512-iruZ7j14oBbRYJC5cP0/vTU7YOWjN+J1ZskEGoF78tFzXdkK2hbCL/3TRZN8XB+MuvFhvOHMp7WkOCBO4VEL5g== - dependencies: - commander "~2.17.1" - source-map "~0.6.1" - source-map-support "~0.5.6" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timers-browserify@^2.0.4: - version "2.0.10" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" - integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= - -trim-trailing-lines@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.1.tgz#e0ec0810fd3c3f1730516b45f49083caaf2774d9" - integrity sha512-bWLv9BbWbbd7mlqqs2oQYnLD/U/ZqeJeJwbO0FG2zA1aTq+HTvxfHNKFa/HGCVyJpDiioUYaBhfiT6rgk+l4mg== - -trim@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - -trough@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.3.tgz#e29bd1614c6458d44869fc28b255ab7857ef7c24" - integrity sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw== - -tslib@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -uglify-es@^3.3.4: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== - dependencies: - commander "~2.13.0" - source-map "~0.6.1" - -uglify-js@^3.4.8: - version "3.4.9" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" - integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== - dependencies: - commander "~2.17.1" - source-map "~0.6.1" - -uglify-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/uglify-loader/-/uglify-loader-3.0.0.tgz#7a3a524797bdc3e8a75c242aad17b2abed9fce15" - integrity sha512-eE+Gt+rR0Yv7hfE8qxkl/FnNp+fX+9yH8hS9jZSngzy6gmYL9/m9/mQRnKj863k/vVSL7B0OEyGOC2Li0aQfSg== - dependencies: - loader-utils "^1.1.0" - source-map "^0.7.3" - uglify-js "^3.4.8" - -uglifyjs-webpack-plugin@^1.2.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz#75f548160858163a08643e086d5fefe18a5d67de" - integrity sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw== - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - schema-utils "^0.4.5" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - uglify-es "^3.3.4" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -unherit@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.1.tgz#132748da3e88eab767e08fabfbb89c5e9d28628c" - integrity sha512-+XZuV691Cn4zHsK0vkKYwBEwB74T3IZIcxrgn2E4rKwTfFyI1zCh7X7grwh9Re08fdPlarIdyWgI8aVB3F5A5g== - dependencies: - inherits "^2.0.1" - xtend "^4.0.1" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" - integrity sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" - integrity sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg== - -unified@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" - integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-plain-obj "^1.1.0" - trough "^1.0.0" - vfile "^2.0.0" - x-is-string "^0.1.0" - -union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^0.4.3" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unique-filename@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" - integrity sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM= - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" - integrity sha1-22Z258fMBimHj/GWCXx4hVrp9Ks= - dependencies: - imurmurhash "^0.1.4" - -unist-util-find-all-after@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.2.tgz#9be49cfbae5ca1566b27536670a92836bf2f8d6d" - integrity sha512-nDl79mKpffXojLpCimVXnxhlH/jjaTnDuScznU9J4jjsaUtBdDbxmlc109XtcqxY4SDO0SwzngsxxW8DIISt1w== - dependencies: - unist-util-is "^2.0.0" - -unist-util-is@^2.0.0, unist-util-is@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-2.1.2.tgz#1193fa8f2bfbbb82150633f3a8d2eb9a1c1d55db" - integrity sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw== - -unist-util-remove-position@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.2.tgz#86b5dad104d0bbfbeb1db5f5c92f3570575c12cb" - integrity sha512-XxoNOBvq1WXRKXxgnSYbtCF76TJrRoe5++pD4cCBsssSiWSnPEktyFrFLE8LTk3JW5mt9hB0Sk5zn4x/JeWY7Q== - dependencies: - unist-util-visit "^1.1.0" - -unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" - integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== - -unist-util-visit-parents@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.0.1.tgz#63fffc8929027bee04bfef7d2cce474f71cb6217" - integrity sha512-6B0UTiMfdWql4cQ03gDTCSns+64Zkfo2OCbK31Ov0uMizEz+CJeAp0cgZVb5Fhmcd7Bct2iRNywejT0orpbqUA== - dependencies: - unist-util-is "^2.1.2" - -unist-util-visit@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.0.tgz#1cb763647186dc26f5e1df5db6bd1e48b3cc2fb1" - integrity sha512-FiGu34ziNsZA3ZUteZxSFaczIjGmksfSgdKqBfOejrrfzyUy5b7YrlzT1Bcvi+djkYDituJDy2XB7tGTeBieKw== - dependencies: - unist-util-visit-parents "^2.0.0" - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.0.5: - version "1.1.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" - integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" - integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== - dependencies: - loader-utils "^1.1.0" - mime "^2.0.3" - schema-utils "^1.0.0" - -url-polyfill@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/url-polyfill/-/url-polyfill-1.1.0.tgz#d34e1a596d954b864bc8608f84c592820df422db" - integrity sha512-QAbzqCwd84yA6VyjV30aZXla+lrRmczDurvlsVnK+tFOu677ZNGz8shcFWQRp5BF9/z7qvNiCQLqpWPtVoUEBg== - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@^1.0.0, util.promisify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.10.3: - version "0.10.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== - dependencies: - inherits "2.0.3" - -v8-compile-cache@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" - integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -vendors@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801" - integrity sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ== - -vfile-location@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.3.tgz#083ba80e50968e8d420be49dd1ea9a992131df77" - integrity sha512-zM5/l4lfw1CBoPx3Jimxoc5RNDAHHpk6AM6LM0pTIkm5SUSsx8ZekZ0PVdf0WEZ7kjlhSt7ZlqbRL6Cd6dBs6A== - -vfile-message@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.0.1.tgz#51a2ccd8a6b97a7980bb34efb9ebde9632e93677" - integrity sha512-vSGCkhNvJzO6VcWC6AlJW4NtYOVtS+RgCaqFIYUjoGIlHnFL+i0LbtYvonDWOMcB97uTPT4PRsyYY7REWC9vug== - dependencies: - unist-util-stringify-position "^1.1.1" - -vfile@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" - integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== - dependencies: - is-buffer "^1.1.4" - replace-ext "1.0.0" - unist-util-stringify-position "^1.0.0" - vfile-message "^1.0.0" - -vm-browserify@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= - dependencies: - indexof "0.0.1" - -watchpack@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== - dependencies: - chokidar "^2.0.2" - graceful-fs "^4.1.2" - neo-async "^2.5.0" - -webpack-cli@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.2.tgz#17d7e01b77f89f884a2bbf9db545f0f6a648e746" - integrity sha512-Cnqo7CeqeSvC6PTdts+dywNi5CRlIPbLx1AoUPK2T6vC1YAugMG3IOoO9DmEscd+Dghw7uRlnzV1KwOe5IrtgQ== - dependencies: - chalk "^2.4.1" - cross-spawn "^6.0.5" - enhanced-resolve "^4.1.0" - global-modules-path "^2.3.0" - import-local "^2.0.0" - interpret "^1.1.0" - loader-utils "^1.1.0" - supports-color "^5.5.0" - v8-compile-cache "^2.0.2" - yargs "^12.0.2" - -webpack-sources@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.2.0.tgz#18181e0d013fce096faf6f8e6d41eeffffdceac2" - integrity sha512-9BZwxR85dNsjWz3blyxdOhTgtnQvv3OEs5xofI0wPYTwu5kaWxS08UuD1oI7WLBLpRO+ylf0ofnXLXWmGb2WMw== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-sources@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" - integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@^4.25.1: - version "4.25.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.25.1.tgz#4f459fbaea0f93440dc86c89f771bb3a837cfb6d" - integrity sha512-T0GU/3NRtO4tMfNzsvpdhUr8HnzA4LTdP2zd+e5zd6CdOH5vNKHnAlO+DvzccfhPdzqRrALOFcjYxx7K5DWmvA== - dependencies: - "@webassemblyjs/ast" "1.7.11" - "@webassemblyjs/helper-module-context" "1.7.11" - "@webassemblyjs/wasm-edit" "1.7.11" - "@webassemblyjs/wasm-parser" "1.7.11" - acorn "^5.6.2" - acorn-dynamic-import "^3.0.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^1.0.0" - enhanced-resolve "^4.1.0" - eslint-scope "^4.0.0" - json-parse-better-errors "^1.0.2" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^0.4.4" - tapable "^1.1.0" - uglifyjs-webpack-plugin "^1.2.4" - watchpack "^1.5.0" - webpack-sources "^1.3.0" - -whatwg-fetch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.14, which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - -worker-farm@^1.5.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" - integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== - dependencies: - errno "~0.1.7" - -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= - dependencies: - mkdirp "^0.5.1" - -x-is-string@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" - integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= - -xregexp@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" - integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== - -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.0, yallist@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" - integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= - -yargs-parser@^10.0.0, yargs-parser@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - -yargs@^12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" - integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== - dependencies: - cliui "^4.0.0" - decamelize "^2.0.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^10.1.0" |