Initial commit.
This commit is contained in:
commit
271568e674
20 changed files with 1426 additions and 0 deletions
2
.editorconfig
Normal file
2
.editorconfig
Normal file
|
@ -0,0 +1,2 @@
|
|||
[*]
|
||||
insert_final_newline=true
|
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# batch files are specific to windows and always crlf
|
||||
*.bat eol=crlf
|
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
!.vscode/extensions.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
**/*.class
|
||||
**/.idea/$CACHE_FILE$
|
||||
**/.idea/$PRODUCT_WORKSPACE_FILE$
|
||||
**/.idea/**/dataSources.ids
|
||||
**/.idea/**/dataSources.local.xml
|
||||
**/.idea/**/dataSources/
|
||||
**/.idea/**/dbnavigator.xml
|
||||
**/.idea/**/dictionaries
|
||||
**/.idea/**/dynamic.xml
|
||||
**/.idea/**/gradle.xml
|
||||
**/.idea/**/libraries
|
||||
**/.idea/**/shelf
|
||||
**/.idea/**/sqlDataSources.xml
|
||||
**/.idea/**/tasks.xml
|
||||
**/.idea/**/uiDesigner.xml
|
||||
**/.idea/**/usage.statistics.xml
|
||||
**/.idea/**/workspace.xml
|
||||
*.code-workspace
|
||||
*.iws
|
||||
*.sublime-*
|
||||
.DS_Store
|
||||
.classpath
|
||||
.gradle
|
||||
.kobalt
|
||||
.nb-gradle
|
||||
.project
|
||||
.settings
|
||||
.vscode/*
|
||||
/bin
|
||||
/build
|
||||
/deploy
|
||||
/dist
|
||||
/gen
|
||||
/gradle.properties
|
||||
/local.properties
|
||||
/out
|
||||
/proguard-project.txt
|
||||
/project.properties
|
||||
/target
|
||||
/test-output
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
kobaltBuild
|
||||
kobaltw*-test
|
16
.idea/checkstyle-idea.xml
generated
Normal file
16
.idea/checkstyle-idea.xml
generated
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CheckStyle-IDEA">
|
||||
<option name="configuration">
|
||||
<map>
|
||||
<entry key="checkstyle-version" value="8.24" />
|
||||
<entry key="copy-libs" value="true" />
|
||||
<entry key="location-0" value="BUNDLED:(bundled):Sun Checks" />
|
||||
<entry key="location-1" value="BUNDLED:(bundled):Google Checks" />
|
||||
<entry key="scan-before-checkin" value="false" />
|
||||
<entry key="scanscope" value="JavaOnly" />
|
||||
<entry key="suppress-errors" value="false" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Erik's Code Style" />
|
||||
</state>
|
||||
</component>
|
6
.idea/copyright/Erik_s_Copyright_Notice.xml
generated
Normal file
6
.idea/copyright/Erik_s_Copyright_Notice.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="&#36;file.fileName Copyright (c) &#36;today.year, Erik C. Thauvin (erik@thauvin.net) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." />
|
||||
<option name="myName" value="Erik's Copyright Notice" />
|
||||
</copyright>
|
||||
</component>
|
3
.idea/copyright/profiles_settings.xml
generated
Normal file
3
.idea/copyright/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="Erik's Copyright Notice" />
|
||||
</component>
|
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
53
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
53
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,53 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<option name="myLocal" value="true" />
|
||||
<inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="TOP_LEVEL_CLASS_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="INNER_CLASS_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="METHOD_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="FIELD_OPTIONS">
|
||||
<value>
|
||||
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
|
||||
<option name="REQUIRED_TAGS" value="" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="IGNORE_DEPRECATED" value="false" />
|
||||
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
|
||||
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
|
||||
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
|
||||
<option name="myAdditionalJavadocTags" value="created" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="REPORT_VARIABLES" value="true" />
|
||||
<option name="REPORT_PARAMETERS" value="false" />
|
||||
<option name="REPORT_CATCH_PARAMETERS" value="false" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
|
||||
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnnecessarySemicolon" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
|
||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="false" />
|
||||
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
13
.idea/misc.xml
generated
Normal file
13
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AnalysisProjectProfileManager">
|
||||
<option name="PROJECT_PROFILE" />
|
||||
<option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
|
||||
<list size="0" />
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_12" project-jdk-name="12" project-jdk-type="JavaSDK" />
|
||||
<component name="SuppressionsComponent">
|
||||
<option name="suppComments" value="[]" />
|
||||
</component>
|
||||
</project>
|
271
build.gradle.kts
Normal file
271
build.gradle.kts
Normal file
|
@ -0,0 +1,271 @@
|
|||
import com.jfrog.bintray.gradle.tasks.BintrayUploadTask
|
||||
import org.jetbrains.dokka.gradle.LinkMapping
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import java.io.FileInputStream
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
jacoco
|
||||
java
|
||||
kotlin("jvm") version "1.3.50"
|
||||
`maven-publish`
|
||||
id("com.github.ben-manes.versions") version "0.25.0"
|
||||
id("com.gradle.build-scan") version "2.4.2"
|
||||
id("com.jfrog.bintray") version "1.8.4"
|
||||
id("io.gitlab.arturbosch.detekt") version "1.0.1"
|
||||
id("net.thauvin.erik.gradle.semver") version "1.0.4"
|
||||
id("org.jetbrains.dokka") version "0.9.18"
|
||||
id("org.jetbrains.kotlin.kapt").version("1.3.50")
|
||||
id("org.jmailen.kotlinter") version "2.1.1"
|
||||
id("org.sonarqube") version "2.7.1"
|
||||
}
|
||||
|
||||
group = "net.thauvin.erik"
|
||||
description = "Akismet for Kotlin/Java, a client library for accesssing the Automattic Kismet (Akismet) spam comments filtering service."
|
||||
|
||||
val gitHub = "ethauvin/$name"
|
||||
val mavenUrl = "https://github.com/$gitHub"
|
||||
val deployDir = "deploy"
|
||||
var isRelease = "release" in gradle.startParameter.taskNames
|
||||
|
||||
var semverProcessor = "net.thauvin.erik:semver:1.2.0"
|
||||
|
||||
val publicationName = "mavenJava"
|
||||
|
||||
// Load local.properties
|
||||
File("local.properties").apply {
|
||||
if (exists()) {
|
||||
FileInputStream(this).use { fis ->
|
||||
Properties().apply {
|
||||
load(fis)
|
||||
forEach { (k, v) ->
|
||||
extra[k as String] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
kapt(semverProcessor)
|
||||
implementation(semverProcessor)
|
||||
|
||||
implementation("javax.servlet:javax.servlet-api:4.0.1")
|
||||
implementation("org.mockito:mockito-core:3.0.0")
|
||||
|
||||
compile("com.squareup.okhttp3:okhttp:4.2.0")
|
||||
compile("com.squareup.okhttp3:logging-interceptor:4.2.0")
|
||||
|
||||
compile(kotlin("stdlib"))
|
||||
|
||||
testImplementation("org.testng:testng:7.0.0")
|
||||
}
|
||||
|
||||
kapt {
|
||||
arguments {
|
||||
arg("semver.project.dir", projectDir)
|
||||
}
|
||||
}
|
||||
|
||||
detekt {
|
||||
input = files("src/main/kotlin", "src/test/kotlin")
|
||||
filters = ".*/resources/.*,.*/build/.*"
|
||||
baseline = project.rootDir.resolve("detekt-baseline.xml")
|
||||
}
|
||||
|
||||
kotlinter {
|
||||
ignoreFailures = false
|
||||
reporters = arrayOf("html")
|
||||
experimentalRules = false
|
||||
disabledRules = arrayOf("import-ordering")
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.3"
|
||||
}
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property("sonar.projectKey", "ethauvin_$name")
|
||||
property("sonar.sourceEncoding", "UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
val sourcesJar by tasks.creating(Jar::class) {
|
||||
archiveClassifier.set("sources")
|
||||
from(sourceSets.getByName("main").allSource)
|
||||
}
|
||||
|
||||
val javadocJar by tasks.creating(Jar::class) {
|
||||
dependsOn(tasks.dokka)
|
||||
from(tasks.dokka)
|
||||
archiveClassifier.set("javadoc")
|
||||
description = "Assembles a JAR of the generated Javadoc."
|
||||
group = JavaBasePlugin.DOCUMENTATION_GROUP
|
||||
}
|
||||
|
||||
tasks {
|
||||
withType<Test> {
|
||||
useTestNG()
|
||||
}
|
||||
|
||||
withType<JacocoReport> {
|
||||
reports {
|
||||
xml.isEnabled = true
|
||||
html.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
|
||||
withType<GenerateMavenPom> {
|
||||
destination = file("$projectDir/pom.xml")
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn(sourcesJar, javadocJar)
|
||||
}
|
||||
|
||||
clean {
|
||||
doLast {
|
||||
project.delete(fileTree(deployDir))
|
||||
}
|
||||
}
|
||||
|
||||
dokka {
|
||||
outputFormat = "html"
|
||||
outputDirectory = "$buildDir/javadoc"
|
||||
jdkVersion = 8
|
||||
val mapping = LinkMapping().apply {
|
||||
dir = "src/main/kotlin"
|
||||
url = "https://github.com/ethauvin/$name/blob/${project.version}/src/main/kotlin"
|
||||
suffix = "#L"
|
||||
}
|
||||
linkMappings = arrayListOf(mapping)
|
||||
includeNonPublic = false
|
||||
}
|
||||
|
||||
val copyToDeploy by registering(Copy::class) {
|
||||
from(configurations.runtime) {
|
||||
exclude("annotations-*.jar")
|
||||
}
|
||||
from(jar)
|
||||
into(deployDir)
|
||||
}
|
||||
|
||||
register("deploy") {
|
||||
description = "Copies all needed files to the $deployDir directory."
|
||||
group = PublishingPlugin.PUBLISH_TASK_GROUP
|
||||
dependsOn("build", "jar")
|
||||
outputs.dir(deployDir)
|
||||
inputs.files(copyToDeploy)
|
||||
mustRunAfter("clean")
|
||||
}
|
||||
|
||||
val gitIsDirty by registering(Exec::class) {
|
||||
description = "Fails if git has uncommitted changes."
|
||||
group = "verification"
|
||||
commandLine("git", "diff", "--quiet", "--exit-code")
|
||||
}
|
||||
|
||||
val gitTag by registering(Exec::class) {
|
||||
description = "Tags the local repository with version ${project.version}"
|
||||
group = PublishingPlugin.PUBLISH_TASK_GROUP
|
||||
dependsOn(gitIsDirty)
|
||||
if (isRelease) {
|
||||
commandLine("git", "tag", "-a", project.version, "-m", "Version ${project.version}")
|
||||
}
|
||||
}
|
||||
|
||||
val bintrayUpload by existing(BintrayUploadTask::class) {
|
||||
dependsOn(publishToMavenLocal, gitTag)
|
||||
}
|
||||
|
||||
buildScan {
|
||||
termsOfServiceUrl = "https://gradle.com/terms-of-service"
|
||||
termsOfServiceAgree = "yes"
|
||||
}
|
||||
|
||||
register("release") {
|
||||
description = "Publishes version ${project.version} to Bintray."
|
||||
group = PublishingPlugin.PUBLISH_TASK_GROUP
|
||||
dependsOn("wrapper", bintrayUpload)
|
||||
}
|
||||
|
||||
"sonarqube" {
|
||||
dependsOn("jacocoTestReport")
|
||||
}
|
||||
}
|
||||
|
||||
fun findProperty(s: String) = project.findProperty(s) as String?
|
||||
bintray {
|
||||
user = findProperty("bintray.user")
|
||||
key = findProperty("bintray.apikey")
|
||||
publish = isRelease
|
||||
setPublications(publicationName)
|
||||
pkg.apply {
|
||||
repo = "maven"
|
||||
name = project.name
|
||||
desc = description
|
||||
websiteUrl = mavenUrl
|
||||
issueTrackerUrl = "$mavenUrl/issues"
|
||||
githubRepo = gitHub
|
||||
githubReleaseNotesFile = "README.md"
|
||||
vcsUrl = "$mavenUrl.git"
|
||||
setLabels("kotlin", "java", "akismet", "comments", "spam", "blog", "automattic", "kismet")
|
||||
publicDownloadNumbers = true
|
||||
version.apply {
|
||||
name = project.version as String
|
||||
desc = description
|
||||
vcsTag = project.version as String
|
||||
gpg.apply {
|
||||
sign = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>(publicationName) {
|
||||
from(components["java"])
|
||||
artifact(sourcesJar)
|
||||
artifact(javadocJar)
|
||||
pom.withXml {
|
||||
asNode().apply {
|
||||
appendNode("name", project.name)
|
||||
appendNode("description", project.description)
|
||||
appendNode("url", mavenUrl)
|
||||
|
||||
appendNode("licenses").appendNode("license").apply {
|
||||
appendNode("name", "BSD 3-Clause")
|
||||
appendNode("url", "https://opensource.org/licenses/BSD-3-Clause")
|
||||
}
|
||||
|
||||
appendNode("developers").appendNode("developer").apply {
|
||||
appendNode("id", "ethauvin")
|
||||
appendNode("name", "Erik C. Thauvin")
|
||||
appendNode("email", "erik@thauvin.net")
|
||||
}
|
||||
|
||||
appendNode("scm").apply {
|
||||
appendNode("connection", "scm:git:$mavenUrl.git")
|
||||
appendNode("developerConnection", "scm:git:git@github.com:$gitHub.git")
|
||||
appendNode("url", mavenUrl)
|
||||
}
|
||||
|
||||
appendNode("issueManagement").apply {
|
||||
appendNode("system", "GitHub")
|
||||
appendNode("url", "$mavenUrl/issues")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
detekt-baseline.xml
Normal file
9
detekt-baseline.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" ?>
|
||||
<SmellBaseline>
|
||||
<Blacklist></Blacklist>
|
||||
<Whitelist>
|
||||
<ID>ComplexMethod:Akismet.kt$Akismet$fun checkComment(userIp: String, userAgent: String, referrer: String = "", permalink: String = "", type: String = "", author: String = "", authorEmail: String = "", authorUrl: String = "", content: String = "", dateGmt: String = "", postModifiedGmt: String = "", blogLang: String = "", blogCharset: String = "", userRole: String = "", recheckReason: String = "", isTest: Boolean = false, other: Map<String, String> = emptyMap() ): Boolean</ID>
|
||||
<ID>LongMethod:Akismet.kt$Akismet$fun checkComment(userIp: String, userAgent: String, referrer: String = "", permalink: String = "", type: String = "", author: String = "", authorEmail: String = "", authorUrl: String = "", content: String = "", dateGmt: String = "", postModifiedGmt: String = "", blogLang: String = "", blogCharset: String = "", userRole: String = "", recheckReason: String = "", isTest: Boolean = false, other: Map<String, String> = emptyMap() ): Boolean</ID>
|
||||
<ID>LongParameterList:Akismet.kt$Akismet$(userIp: String, userAgent: String, referrer: String = "", permalink: String = "", type: String = "", author: String = "", authorEmail: String = "", authorUrl: String = "", content: String = "", dateGmt: String = "", postModifiedGmt: String = "", blogLang: String = "", blogCharset: String = "", userRole: String = "", recheckReason: String = "", isTest: Boolean = false, other: Map<String, String> = emptyMap() )</ID>
|
||||
</Whitelist>
|
||||
</SmellBaseline>
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
188
gradlew
vendored
Normal file
188
gradlew
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
100
gradlew.bat
vendored
Normal file
100
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
10
settings.gradle.kts
Normal file
10
settings.gradle.kts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user manual at https://docs.gradle.org/5.6.2/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = "akismet-kotlin"
|
521
src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt
Normal file
521
src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt
Normal file
|
@ -0,0 +1,521 @@
|
|||
/*
|
||||
* Akismet.kt
|
||||
*
|
||||
* Copyright (c) 2019, Erik C. Thauvin (erik@thauvin.net)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.thauvin.erik.akismet
|
||||
|
||||
import net.thauvin.erik.semver.Version
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import java.io.IOException
|
||||
import java.util.logging.Level
|
||||
import java.util.logging.Logger
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
|
||||
/**
|
||||
* Akismet Kotlin/Java Client Library
|
||||
*/
|
||||
@Version(properties = "version.properties", type = "kt")
|
||||
open class Akismet(apiKey: String, blog: String) {
|
||||
@Suppress("unused")
|
||||
companion object {
|
||||
/** A blog comment. */
|
||||
const val COMMENT_TYPE_COMMENT = "comment"
|
||||
/** A top-level forum post. */
|
||||
const val COMMENT_TYPE_FORUM_POST = "forum-post"
|
||||
/** A reply to a top-level forum post. */
|
||||
const val COMMENT_TYPE_REPLY = "reply"
|
||||
/** A blog post. */
|
||||
const val COMMENT_TYPE_BLOG_POST = "blog-post"
|
||||
/** A contact form or feedback form submission. */
|
||||
const val COMMENT_TYPE_CONTACT_FORM = "contact-form"
|
||||
/** A new user account. */
|
||||
const val COMMENT_TYPE_SIGNUP = "signup"
|
||||
/** A message sent between just a few users. */
|
||||
const val COMMENT_TYPE_MESSAGE = "message"
|
||||
/** Administrator role */
|
||||
const val ADMIN_ROLE = "administrator"
|
||||
}
|
||||
|
||||
private val apiEndPoint = "https://%s.akismet.com/1.1/%s"
|
||||
private val libUserAgent = "${GeneratedVersion.PROJECT}/${GeneratedVersion.VERSION}"
|
||||
private val verifyMethod = "verify-key"
|
||||
private var apiKey: String
|
||||
private var blog: String
|
||||
private var client: OkHttpClient
|
||||
|
||||
var isValidKey: Boolean = false
|
||||
private set
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var proTip: String = ""
|
||||
private set
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var error: String = ""
|
||||
private set
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
var degugHelp: String = ""
|
||||
private set
|
||||
|
||||
val logger: Logger by lazy { Logger.getLogger(Akismet::class.java.simpleName) }
|
||||
|
||||
init {
|
||||
require(!apiKey.isBlank() || apiKey.length != 12) { "An Akismet API key must be specified." }
|
||||
require(!blog.isBlank()) { "A Blog URL must be specified." }
|
||||
|
||||
this.apiKey = apiKey
|
||||
this.blog = blog
|
||||
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
val logging = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
|
||||
override fun log(message: String) {
|
||||
logger.log(Level.FINE, message)
|
||||
}
|
||||
})
|
||||
logging.level = HttpLoggingInterceptor.Level.BODY
|
||||
client = OkHttpClient.Builder().addInterceptor(logging).build()
|
||||
} else {
|
||||
client = OkHttpClient()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key Verification
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#verify-key">Akismet API</a>
|
||||
*/
|
||||
fun verifyKey(): Boolean {
|
||||
val params = HashMap<String, String>()
|
||||
params["key"] = apiKey
|
||||
params["blog"] = blog
|
||||
isValidKey = executeMethod(verifyMethod, FormBody.Builder().build())
|
||||
return isValidKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment Check using [HttpServletRequest][request] content.
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#comment-check">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun checkComment(
|
||||
request: HttpServletRequest,
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
return checkComment(
|
||||
userIp = request.remoteAddr,
|
||||
userAgent = request.getHeader("User-Agent"),
|
||||
referrer = request.getHeader("Referer"),
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = buildPhpVars(request, other))
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment Check
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#comment-check">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun checkComment(
|
||||
userIp: String,
|
||||
userAgent: String,
|
||||
referrer: String = "",
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
|
||||
require(!(userIp.isBlank() && userAgent.isBlank())) { "userIp and/or userAgent are required." }
|
||||
|
||||
return executeMethod(
|
||||
"comment-check",
|
||||
buildFormBody(
|
||||
userIp = userIp,
|
||||
userAgent = userAgent,
|
||||
referrer = referrer,
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = other))
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit Spam
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#submit-spam">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun submitSpam(
|
||||
request: HttpServletRequest,
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
return submitSpam(
|
||||
userIp = request.remoteAddr,
|
||||
userAgent = request.getHeader("User-Agent"),
|
||||
referrer = request.getHeader("Referer"),
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = buildPhpVars(request, other))
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit Spam (missed spam)
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#submit-spam">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun submitSpam(
|
||||
userIp: String,
|
||||
userAgent: String,
|
||||
referrer: String = "",
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
return executeMethod(
|
||||
"submit-spam",
|
||||
buildFormBody(
|
||||
userIp = userIp,
|
||||
userAgent = userAgent,
|
||||
referrer = referrer,
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = other))
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit Ham (false positives)
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#submit-ham">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun submitHam(
|
||||
request: HttpServletRequest,
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
return submitHam(
|
||||
userIp = request.remoteAddr,
|
||||
userAgent = request.getHeader("User-Agent"),
|
||||
referrer = request.getHeader("Referer"),
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = buildPhpVars(request, other))
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit Ham
|
||||
*
|
||||
* @see <a href="https://akismet.com/development/api/#submit-ham">Akismet API</a>
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun submitHam(
|
||||
userIp: String,
|
||||
userAgent: String,
|
||||
referrer: String = "",
|
||||
permalink: String = "",
|
||||
type: String = "",
|
||||
author: String = "",
|
||||
authorEmail: String = "",
|
||||
authorUrl: String = "",
|
||||
content: String = "",
|
||||
dateGmt: String = "",
|
||||
postModifiedGmt: String = "",
|
||||
blogLang: String = "",
|
||||
blogCharset: String = "",
|
||||
userRole: String = "",
|
||||
isTest: Boolean = false,
|
||||
recheckReason: String = "",
|
||||
other: Map<String, String> = emptyMap()
|
||||
): Boolean {
|
||||
return executeMethod(
|
||||
"submit-ham",
|
||||
buildFormBody(
|
||||
userIp = userIp,
|
||||
userAgent = userAgent,
|
||||
referrer = referrer,
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
dateGmt = dateGmt,
|
||||
postModifiedGmt = postModifiedGmt,
|
||||
blogLang = blogLang,
|
||||
blogCharset = blogCharset,
|
||||
userRole = userRole,
|
||||
isTest = isTest,
|
||||
recheckReason = recheckReason,
|
||||
other = other))
|
||||
}
|
||||
|
||||
private fun executeMethod(method: String, formBody: FormBody): Boolean {
|
||||
val apiUrl = buildApiUrl(method).toHttpUrlOrNull()
|
||||
if (apiUrl != null) {
|
||||
val request = Request.Builder().url(apiUrl).post(formBody).header("User-Agent", libUserAgent).build()
|
||||
try {
|
||||
val result = client.newCall(request).execute()
|
||||
proTip = result.header("x-akismet-pro-tip", "").toString()
|
||||
error = result.header("x-akismet-error", "").toString()
|
||||
degugHelp = result.header("X-akismet-debug-help", "").toString()
|
||||
val body = result.body?.string()
|
||||
if (body != null) {
|
||||
val response = body.trim()
|
||||
if (response.equals("valid", true) ||
|
||||
response.equals("true", true) ||
|
||||
response.startsWith("Thanks", true)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
logger.log(Level.SEVERE, "An IO error occurred while communicating with the Akismet service.", e)
|
||||
}
|
||||
} else {
|
||||
logger.severe("Invalid API end point URL: $method. The API Key is likely invalid.")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun buildApiUrl(method: String): String {
|
||||
if (method == verifyMethod) {
|
||||
return String.format(apiEndPoint, "rest", method)
|
||||
}
|
||||
return String.format(apiEndPoint, apiKey, method)
|
||||
}
|
||||
|
||||
private fun buildPhpVars(request: HttpServletRequest, other: Map<String, String>): HashMap<String, String> {
|
||||
val params = HashMap<String, String>()
|
||||
params["REMOTE_ADDR"] = request.remoteAddr
|
||||
params["REQUEST_URI"] = request.requestURI
|
||||
|
||||
val names = request.headerNames
|
||||
while (names.hasMoreElements()) {
|
||||
val name = names.nextElement()
|
||||
if (!name.equals("cookie", true)) {
|
||||
params["HTTP_${name.toUpperCase()}"] = request.getHeader(name)
|
||||
}
|
||||
}
|
||||
|
||||
if (other.isEmpty()) {
|
||||
params.putAll(other)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
private fun buildFormBody(
|
||||
userIp: String,
|
||||
userAgent: String,
|
||||
referrer: String,
|
||||
permalink: String,
|
||||
type: String,
|
||||
author: String,
|
||||
authorEmail: String,
|
||||
authorUrl: String,
|
||||
content: String,
|
||||
dateGmt: String,
|
||||
postModifiedGmt: String,
|
||||
blogLang: String,
|
||||
blogCharset: String,
|
||||
userRole: String,
|
||||
isTest: Boolean,
|
||||
recheckReason: String,
|
||||
other: Map<String, String>
|
||||
): FormBody {
|
||||
return FormBody.Builder().apply {
|
||||
add("blog", blog)
|
||||
add("user_ip", userIp)
|
||||
add("user_agent", userAgent)
|
||||
|
||||
if (referrer.isNotBlank()) {
|
||||
add("referrer", referrer)
|
||||
}
|
||||
if (permalink.isNotBlank()) {
|
||||
add("permalink", permalink)
|
||||
}
|
||||
if (type.isNotBlank()) {
|
||||
add("comment_type", type)
|
||||
}
|
||||
if (author.isNotBlank()) {
|
||||
add("comment_author", author)
|
||||
}
|
||||
if (authorEmail.isNotBlank()) {
|
||||
add("comment_author_email", authorEmail)
|
||||
}
|
||||
if (authorUrl.isNotBlank()) {
|
||||
add("comment_author_url", authorUrl)
|
||||
}
|
||||
if (content.isNotBlank()) {
|
||||
add("comment_content", content)
|
||||
}
|
||||
if (dateGmt.isNotBlank()) {
|
||||
add("comment_date_gmt", dateGmt)
|
||||
}
|
||||
if (postModifiedGmt.isNotBlank()) {
|
||||
add("comment_post_modified_gmt", postModifiedGmt)
|
||||
}
|
||||
if (blogLang.isNotBlank()) {
|
||||
add("blog_lang", blogLang)
|
||||
}
|
||||
if (blogCharset.isNotBlank()) {
|
||||
add("blog_charset", blogCharset)
|
||||
}
|
||||
if (userRole.isNotBlank()) {
|
||||
add("user_role", userRole)
|
||||
}
|
||||
if (isTest) {
|
||||
add("is_test", "true")
|
||||
}
|
||||
if (recheckReason.isNotBlank()) {
|
||||
add("recheck_reason", recheckReason)
|
||||
}
|
||||
|
||||
other.forEach { (k, v) -> add(k, v) }
|
||||
}.build()
|
||||
}
|
||||
}
|
156
src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt
Normal file
156
src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* AkismetTest.kt
|
||||
*
|
||||
* Copyright (c) 2019, Erik C. Thauvin (erik@thauvin.net)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.akismet
|
||||
|
||||
import org.mockito.Mockito
|
||||
import org.testng.Assert.assertFalse
|
||||
import org.testng.Assert.assertTrue
|
||||
import org.testng.Assert.expectThrows
|
||||
import org.testng.annotations.BeforeClass
|
||||
import org.testng.annotations.Test
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.Collections
|
||||
import java.util.Properties
|
||||
import java.util.logging.ConsoleHandler
|
||||
import java.util.logging.Level
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
|
||||
/**
|
||||
* The <code>AkismetTest</code> class.
|
||||
*
|
||||
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
|
||||
* @created 2019-09-17
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
fun getApiKey(): String {
|
||||
var apiKey = System.getenv("AKISMET_API_KEY") ?: ""
|
||||
if (apiKey.isBlank()) {
|
||||
val localProps = File("local.properties")
|
||||
if (localProps.exists())
|
||||
localProps.apply {
|
||||
if (exists()) {
|
||||
FileInputStream(this).use { fis ->
|
||||
Properties().apply {
|
||||
load(fis)
|
||||
apiKey = getProperty("AKISMET_API_KEY", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return apiKey
|
||||
}
|
||||
|
||||
class AkismetTest {
|
||||
private val userIp = "127.0.0.1"
|
||||
private val userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6"
|
||||
private val referrer = "http://www.google.com"
|
||||
private val permalink = "http://yourblogdomainname.com/blog/post=1"
|
||||
private val type = "comment"
|
||||
private val author = "admin"
|
||||
private val authorEmail = "test@test.com"
|
||||
private val authorUrl = "http://www.CheckOutMyCoolSite.com"
|
||||
private val content = "It means a lot that you would take the time to review our software. Thanks again."
|
||||
private val akismet = Akismet(getApiKey(), "http://erik.thauvin.net/blog/")
|
||||
private val request = Mockito.mock(HttpServletRequest::class.java)
|
||||
|
||||
@BeforeClass
|
||||
fun beforeClass() {
|
||||
with(akismet.logger) {
|
||||
addHandler(ConsoleHandler().apply { level = Level.FINE })
|
||||
level = Level.FINE
|
||||
}
|
||||
|
||||
Mockito.`when`(request.remoteAddr).thenReturn(userIp)
|
||||
Mockito.`when`(request.requestURI).thenReturn("/blog/post=1")
|
||||
Mockito.`when`(request.getHeader("User-Agent")).thenReturn(userAgent)
|
||||
Mockito.`when`(request.getHeader("Referer")).thenReturn(referrer)
|
||||
Mockito.`when`(request.getHeader("Cookie")).thenReturn("name=value; name2=value2; name3=value3")
|
||||
Mockito.`when`(request.getHeader("Accept-Encoding")).thenReturn("gzip")
|
||||
Mockito.`when`(request.headerNames)
|
||||
.thenReturn(Collections.enumeration(listOf("User-Agent", "Referer", "Cookie", "Accept-Encoding")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun constructorTest() {
|
||||
expectThrows(IllegalArgumentException::class.java) {
|
||||
Akismet("123456789012", "http://www.foo.com/")
|
||||
Akismet("", "http://www.foo.com/")
|
||||
Akismet("123456789012", "")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyKeyTest() {
|
||||
assertFalse(akismet.isValidKey, "isValidKey -> false")
|
||||
assertTrue(akismet.verifyKey(), "verify_key")
|
||||
assertTrue(akismet.isValidKey, "isValidKey -> true")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkCommentTest() {
|
||||
// assertFalse(akismet.checkComment(userIp = userIp,
|
||||
// userAgent = userAgent,
|
||||
// referrer = referrer,
|
||||
// permalink = permalink,
|
||||
// type = type,
|
||||
// author = author,
|
||||
// authorEmail = authorEmail,
|
||||
// authorUrl = authorUrl,
|
||||
// content = content,
|
||||
// userRole = Akismet.ADMIN_ROLE,
|
||||
// isTest = true), "check_comment -> false")
|
||||
//
|
||||
// assertTrue(akismet.checkComment(userIp = userIp,
|
||||
// userAgent = userAgent,
|
||||
// referrer = referrer,
|
||||
// permalink = permalink,
|
||||
// type = type,
|
||||
// author = author,
|
||||
// authorEmail = authorEmail,
|
||||
// authorUrl = authorUrl,
|
||||
// content = content,
|
||||
// isTest = true), "check_comment -> true")
|
||||
|
||||
assertTrue(akismet.checkComment(request,
|
||||
permalink = permalink,
|
||||
type = type,
|
||||
author = author,
|
||||
authorEmail = authorEmail,
|
||||
authorUrl = authorUrl,
|
||||
content = content,
|
||||
isTest = true), "check_comment(request) -> true")
|
||||
}
|
||||
}
|
9
version.properties
Normal file
9
version.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
#Generated by the Semver Plugin for Gradle
|
||||
#Tue Sep 17 13:40:32 PDT 2019
|
||||
version.buildmeta=
|
||||
version.major=0
|
||||
version.minor=9
|
||||
version.patch=0
|
||||
version.prerelease=beta
|
||||
version.project=Akismet Kotlin
|
||||
version.semver=0.9.0
|
Loading…
Add table
Add a link
Reference in a new issue