diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index c781fdc..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,62 +0,0 @@ -version: 2.1 - -orbs: - sdkman: joshdholtz/sdkman@0.2.0 - -defaults: &defaults - working_directory: ~/repo - environment: - JVM_OPTS: -Xmx3200m - TERM: dumb - CI_NAME: "CircleCI" - -commands: - build_and_test: - parameters: - reports-dir: - type: string - default: "build/reports/test_results" - steps: - - checkout - - sdkman/setup-sdkman - - sdkman/sdkman-install: - candidate: kotlin - version: 2.1.10 - - run: - name: Download dependencies - command: ./bld download - - run: - name: Compile source - command: ./bld compile - - run: - name: Run tests - command: ./bld jacoco -reports-dir=<< parameters.reports-dir >> - - store_test_results: - path: << parameters.reports-dir >> - - store_artifacts: - path: build/reports/jacoco/test/html - -jobs: - bld_jdk17: - <<: *defaults - - docker: - - image: cimg/openjdk:17.0 - - steps: - - build_and_test - - bld_jdk21: - <<: *defaults - - docker: - - image: cimg/openjdk:21.0 - - steps: - - build_and_test - -workflows: - bld: - jobs: - - bld_jdk17 - - bld_jdk21 diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 1f808de..0000000 --- a/.editorconfig +++ /dev/null @@ -1,2 +0,0 @@ -[*] -insert_final_newline = true diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 6ec2ae2..0000000 --- a/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -# 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 diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml deleted file mode 100644 index 8e7d939..0000000 --- a/.github/workflows/bld.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: bld-ci - -on: [push, pull_request, workflow_dispatch] - -env: - ALPHAVANTAGE_API_KEY: ${{ secrets.ALPHAVANTAGE_API_KEY }} - CHATGPT_API_KEY: ${{ secrets.CHATGPT_API_KEY }} - CI_NAME: "GitHub CI" - COVERAGE_JDK: "21" - COVERAGE_KOTLIN: "2.1.0" - EXCHANGERATE_API_KEY: ${{ secrets.EXCHANGERATE_API_KEY }} - KOTLIN_HOME: /usr/share/kotlinc - MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} - MASTODON_HANDLE: ${{ secrets.MASTODON_HANDLE }} - MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} - OWM_API_KEY: ${{ secrets.OWM_API_KEY }} - PINBOARD_API_TOKEN: ${{ secrets.PINBOARD_API_TOKEN }} - -jobs: - build-bld-project: - runs-on: ubuntu-latest - - strategy: - matrix: - java-version: [17, 21, 24] - kotlin-version: [1.9.25, 2.0.20, 2.1.20] - - steps: - - name: Checkout source repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up JDK ${{ matrix.java-version }} with Kotlin ${{ matrix.kotlin-version }} - uses: actions/setup-java@v4 - with: - distribution: "zulu" - java-version: ${{ matrix.java-version }} - - - name: Download dependencies - run: ./bld download - - - name: Compile source - run: ./bld compile - - - name: Run tests - run: ./bld jacoco - - - name: Remove pom.xml - if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN - run: rm -rf pom.xml - - - name: SonarCloud Scan - uses: sonarsource/sonarcloud-github-action@master - if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.kotlin-version == env.COVERAGE_KOTLIN - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d2daf1c..0000000 --- a/.gitignore +++ /dev/null @@ -1,63 +0,0 @@ -.gradle -.DS_Store -build -lib/bld/** -!lib/bld/bld-wrapper.jar -!lib/bld/bld-wrapper.properties -lib/compile/ -lib/runtime/ -lib/standalone/ -lib/test/ - -# IDEA ignores - -# User-specific -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Editor-based Rest Client -.idea/httpRequests - -bin -deploy -local.properties -logs -mobibot.properties -out -/target/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 10b9b0f..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,24 +0,0 @@ -image: fedora:latest - -variables: - CI_NAME: "GitLab CI" - -stages: - - test - -before_script: - - dnf -qy update && dnf -y install zip - - curl -s "https://get.sdkman.io" | bash - - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config - - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config - - source "$HOME/.sdkman/bin/sdkman-init.sh" - - sdk install java - - sdk install kotlin - - source "$HOME/.sdkman/bin/sdkman-init.sh" - -test: - stage: test - script: - - ./bld download - - ./bld compile - - ./bld test diff --git a/.idea/app.iml b/.idea/app.iml deleted file mode 100644 index 2c1fe21..0000000 --- a/.idea/app.iml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/bld.iml b/.idea/bld.iml deleted file mode 100644 index e63e11e..0000000 --- a/.idea/bld.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/bld.xml b/.idea/bld.xml deleted file mode 100644 index 6600cee..0000000 --- a/.idea/bld.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/copyright/BSD_3.xml b/.idea/copyright/BSD_3.xml deleted file mode 100644 index 3c57002..0000000 --- a/.idea/copyright/BSD_3.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index 3203074..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 1e01b48..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/intellij-javadocs-4.0.1.xml b/.idea/intellij-javadocs-4.0.1.xml deleted file mode 100644 index dd24abe..0000000 --- a/.idea/intellij-javadocs-4.0.1.xml +++ /dev/null @@ -1,204 +0,0 @@ - - - - - UPDATE - false - true - - FIELD - METHOD - TYPE - - - PROTECTED - DEFAULT - PUBLIC - - - - - - ^.*(public|protected|private)*.+interface\s+\w+.* - /**\n - * The interface ${name}.\n -<#if element.typeParameters?has_content> * \n -</#if> -<#list element.typeParameters as typeParameter> - * @param <${typeParameter.name}> the type parameter\n -</#list> - */ - - - ^.*(public|protected|private)*.+enum\s+\w+.* - /**\n - * The enum ${name}.\n - */ - - - ^.*(public|protected|private)*.+class\s+\w+.* - /**\n - * The type ${name}.\n -<#if element.typeParameters?has_content> * \n -</#if> -<#list element.typeParameters as typeParameter> - * @param <${typeParameter.name}> the type parameter\n -</#list> - */ - - - .+ - /**\n - * The type ${name}.\n - */ - - - - - .+ - /**\n - * Instantiates a new ${name}.\n -<#if element.parameterList.parameters?has_content> - *\n -</#if> -<#list element.parameterList.parameters as parameter> - * @param ${parameter.name} the ${paramNames[parameter.name]}\n -</#list> -<#if element.throwsList.referenceElements?has_content> - *\n -</#if> -<#list element.throwsList.referenceElements as exception> - * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n -</#list> - */ - - - - - ^.*(public|protected|private)*\s*.*(\w(\s*<.+>)*)+\s+get\w+\s*\(.*\).+ - /**\n - * Gets ${partName}.\n -<#if element.typeParameters?has_content> * \n -</#if> -<#list element.typeParameters as typeParameter> - * @param <${typeParameter.name}> the type parameter\n -</#list> -<#if element.parameterList.parameters?has_content> - *\n -</#if> -<#list element.parameterList.parameters as parameter> - * @param ${parameter.name} the ${paramNames[parameter.name]}\n -</#list> -<#if isNotVoid> - *\n - * @return the ${partName}\n -</#if> -<#if element.throwsList.referenceElements?has_content> - *\n -</#if> -<#list element.throwsList.referenceElements as exception> - * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n -</#list> - */ - - - ^.*(public|protected|private)*\s*.*(void|\w(\s*<.+>)*)+\s+set\w+\s*\(.*\).+ - /**\n - * Sets ${partName}.\n -<#if element.typeParameters?has_content> * \n -</#if> -<#list element.typeParameters as typeParameter> - * @param <${typeParameter.name}> the type parameter\n -</#list> -<#if element.parameterList.parameters?has_content> - *\n -</#if> -<#list element.parameterList.parameters as parameter> - * @param ${parameter.name} the ${paramNames[parameter.name]}\n -</#list> -<#if isNotVoid> - *\n - * @return the ${partName}\n -</#if> -<#if element.throwsList.referenceElements?has_content> - *\n -</#if> -<#list element.throwsList.referenceElements as exception> - * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n -</#list> - */ - - - ^.*((public\s+static)|(static\s+public))\s+void\s+main\s*\(\s*String\s*(\[\s*\]|\.\.\.)\s+\w+\s*\).+ - /**\n - * The entry point of application.\n - - <#if element.parameterList.parameters?has_content> - *\n -</#if> - * @param ${element.parameterList.parameters[0].name} the input arguments\n -<#if element.throwsList.referenceElements?has_content> - *\n -</#if> -<#list element.throwsList.referenceElements as exception> - * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n -</#list> - */ - - - .+ - /**\n - * ${name}<#if isNotVoid> ${return}</#if>.\n -<#if element.typeParameters?has_content> * \n -</#if> -<#list element.typeParameters as typeParameter> - * @param <${typeParameter.name}> the type parameter\n -</#list> -<#if element.parameterList.parameters?has_content> - *\n -</#if> -<#list element.parameterList.parameters as parameter> - * @param ${parameter.name} the ${paramNames[parameter.name]}\n -</#list> -<#if isNotVoid> - *\n - * @return the ${return}\n -</#if> -<#if element.throwsList.referenceElements?has_content> - *\n -</#if> -<#list element.throwsList.referenceElements as exception> - * @throws ${exception.referenceName} the ${exceptionNames[exception.referenceName]}\n -</#list> - */ - - - - - ^.*(public|protected|private)*.+static.*(\w\s\w)+.+ - /**\n - * The constant ${element.getName()}.\n - */ - - - ^.*(public|protected|private)*.*(\w\s\w)+.+ - /**\n - <#if element.parent.isInterface()> - * The constant ${element.getName()}.\n -<#else> - * The ${name}.\n -</#if> */ - - - .+ - /**\n - <#if element.parent.isEnum()> - *${name} ${typeName}.\n -<#else> - * The ${name}.\n -</#if>*/ - - - - - \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index 0273acf..0000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/bld.xml b/.idea/libraries/bld.xml deleted file mode 100644 index 153a060..0000000 --- a/.idea/libraries/bld.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/.idea/libraries/compile.xml b/.idea/libraries/compile.xml deleted file mode 100644 index 99cc0c0..0000000 --- a/.idea/libraries/compile.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/runtime.xml b/.idea/libraries/runtime.xml deleted file mode 100644 index d4069f2..0000000 --- a/.idea/libraries/runtime.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/test.xml b/.idea/libraries/test.xml deleted file mode 100644 index 57ed5ef..0000000 --- a/.idea/libraries/test.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index bccad37..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 55adcb9..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/Run Tests.xml b/.idea/runConfigurations/Run Tests.xml deleted file mode 100644 index 37dc742..0000000 --- a/.idea/runConfigurations/Run Tests.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7b016a8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.compile.nullAnalysis.mode": "automatic" -} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 54e8774..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - -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. diff --git a/README.md b/README.md deleted file mode 100644 index d43ba67..0000000 --- a/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# mobibot - -[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -[![Kotlin](https://img.shields.io/badge/kotlin-2.1.20-7f52ff.svg)](https://kotlinlang.org) -[![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ethauvin_mobibot&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ethauvin_mobibot) -[![GitHub CI](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml/badge.svg)](https://github.com/ethauvin/mobibot/actions/workflows/bld.yml) -[![CircleCI](https://circleci.com/gh/ethauvin/mobibot/tree/master.svg?style=shield)](https://circleci.com/gh/ethauvin/mobibot/tree/master) - -Some very basic instructions: - -```sh - # clone with git or download the ZIP - git clone https://github.com/ethauvin/mobibot.git - - cd mobibot - - # build JAR and deploy - ./bld jar deploy - - cd deploy - - # configure the properties - vi *.properties *.xml - - # help - java -jar mobibot.jar -h - - # launch - /usr/bin/nohup java -jar mobibot.jar & -``` - -For a listing of features, see the [website](https://mobitopia.org/mobibot/). diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml deleted file mode 100644 index ace99d2..0000000 --- a/bitbucket-pipelines.yml +++ /dev/null @@ -1,20 +0,0 @@ -image: ubuntu:latest - -pipelines: - default: - - step: - name: Test with bld - script: - # Install latest Java & Kotlin via SDKMAN! - - apt-get update -qq && apt-get install -y curl zip - - curl -s "https://get.sdkman.io" | bash - - echo sdkman_auto_answer=true > $HOME/.sdkman/etc/config - - echo sdkman_auto_selfupdate=true >> $HOME/.sdkman/etc/config - - source "$HOME/.sdkman/bin/sdkman-init.sh" - - sdk install java - - sdk install kotlin - - source "$HOME/.sdkman/bin/sdkman-init.sh" - # Download, compile and test with bld - - ./bld download - - ./bld compile - - ./bld test diff --git a/bld b/bld deleted file mode 100755 index 77721d6..0000000 --- a/bld +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env sh -java -jar "$(dirname "$0")/lib/bld/bld-wrapper.jar" "$0" --build net.thauvin.erik.MobibotBuild "$@" \ No newline at end of file diff --git a/bld.bat b/bld.bat deleted file mode 100644 index 12ffa36..0000000 --- a/bld.bat +++ /dev/null @@ -1,4 +0,0 @@ -@echo off -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -java -jar "%DIRNAME%/lib/bld/bld-wrapper.jar" "%0" --build net.thauvin.erik.MobibotBuild %* \ No newline at end of file diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml deleted file mode 100644 index 719ca4e..0000000 --- a/config/detekt/baseline.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - CyclomaticComplexMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) - CyclomaticComplexMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - LongMethod:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) - LongMethod:Mobibot.kt$Mobibot.Companion$@JvmStatic @Throws(Exception::class) fun main(args: Array<String>) - LongMethod:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> - LongMethod:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - LongParameterList:Comment.kt$Comment$( channel: String, cmd: String, entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent ) - LongParameterList:EntryLink.kt$EntryLink$( // Link's comments val comments: MutableList<EntryComment> = mutableListOf(), // Tags/categories val tags: MutableList<SyndCategory> = mutableListOf(), // Channel var channel: String, // Creation date var date: Date = Calendar.getInstance().time, // Link's URL var link: String, // Author's login var login: String = "", // Author's nickname var nick: String, // Link's title var title: String ) - MagicNumber:ChatGpt.kt$ChatGpt.Companion$200 - MagicNumber:ChatGpt.kt$ChatGpt.Companion$429 - MagicNumber:Comment.kt$Comment$3 - MagicNumber:CryptoPrices.kt$CryptoPrices$10 - MagicNumber:CurrencyConverter.kt$CurrencyConverter$11 - MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$3 - MagicNumber:CurrencyConverter.kt$CurrencyConverter.Companion$4 - MagicNumber:Cycle.kt$Cycle$10 - MagicNumber:Cycle.kt$Cycle$1000L - MagicNumber:Ignore.kt$Ignore$8 - MagicNumber:Info.kt$Info.Companion$30 - MagicNumber:Info.kt$Info.Companion$365 - MagicNumber:Info.kt$Info.Companion$7 - MagicNumber:Mastodon.kt$Mastodon.Companion$200 - MagicNumber:Mobibot.kt$Mobibot$8 - MagicNumber:Modules.kt$Modules$7 - MagicNumber:Seen.kt$Seen$7 - MagicNumber:SocialManager.kt$SocialManager$1000L - MagicNumber:SocialManager.kt$SocialManager$60L - MagicNumber:StockQuote.kt$StockQuote.Companion$10 - MagicNumber:Tell.kt$Tell$50 - MagicNumber:Tell.kt$Tell$7 - MagicNumber:Users.kt$Users$8 - MagicNumber:Utils.kt$Utils$200 - MagicNumber:Utils.kt$Utils$399 - MagicNumber:Weather2.kt$Weather2.Companion$1.60934 - MagicNumber:Weather2.kt$Weather2.Companion$32 - MagicNumber:Weather2.kt$Weather2.Companion$404 - MagicNumber:Weather2.kt$Weather2.Companion$5 - MagicNumber:Weather2.kt$Weather2.Companion$9 - MagicNumber:WorldTime.kt$WorldTime$14 - MagicNumber:WorldTime.kt$WorldTime$4 - MagicNumber:WorldTime.kt$WorldTime.Companion$3600 - MagicNumber:WorldTime.kt$WorldTime.Companion$60 - MagicNumber:WorldTime.kt$WorldTime.Companion$86.4 - NestedBlockDepth:Addons.kt$Addons$fun add(command: AbstractCommand): Boolean - NestedBlockDepth:Addons.kt$Addons$fun add(module: AbstractModule): Boolean - NestedBlockDepth:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String - NestedBlockDepth:Comment.kt$Comment$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic @Throws(ModuleException::class) fun loadSymbols(apiKey: String?) - NestedBlockDepth:CurrencyConverter.kt$CurrencyConverter.Companion$@JvmStatic fun convertCurrency(apiKey: String?, query: String): Message - NestedBlockDepth:EntryLink.kt$EntryLink$private fun setTags(tags: List<String?>) - NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic @Throws(IOException::class, FeedException::class) fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String - NestedBlockDepth:FeedsManager.kt$FeedsManager.Companion$@JvmStatic fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) - NestedBlockDepth:GoogleSearch.kt$GoogleSearch$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> - NestedBlockDepth:LinksManager.kt$LinksManager$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:Lookup.kt$Lookup$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String - NestedBlockDepth:Posting.kt$Posting$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> - NestedBlockDepth:Tell.kt$Tell$fun send(event: GenericUserEvent) - NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any - NestedBlockDepth:Utils.kt$Utils$@JvmStatic fun saveSerialData(file: String, data: Any, logger: Logger, description: String) - NestedBlockDepth:Weather2.kt$Weather2$override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - NestedBlockDepth:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - ReturnCount:Addons.kt$Addons$fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean - ReturnCount:Addons.kt$Addons$fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean - ReturnCount:ExceptionSanitizer.kt$ExceptionSanitizer$fun ModuleException.sanitize(vararg sanitize: String): ModuleException - ReturnCount:Seen.kt$Seen$override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - ThrowsCount:ChatGpt.kt$ChatGpt.Companion$@JvmStatic @Throws(ModuleException::class) fun chat(query: String, apiKey: String?, maxTokens: Int): String - ThrowsCount:GoogleSearch.kt$GoogleSearch.Companion$@JvmStatic @Throws(ModuleException::class) fun searchGoogle( query: String, apiKey: String?, cseKey: String?, quotaUser: String = ReleaseInfo.PROJECT ): List<Message> - ThrowsCount:Joke.kt$Joke.Companion$@JvmStatic @Throws(ModuleException::class) fun randomJoke(): List<Message> - ThrowsCount:Mastodon.kt$Mastodon.Companion$@JvmStatic @Throws(ModuleException::class) fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String - ThrowsCount:StockQuote.kt$StockQuote.Companion$@JvmStatic @Throws(ModuleException::class) fun getQuote(symbol: String, apiKey: String?): List<Message> - ThrowsCount:StockQuote.kt$StockQuote.Companion$@Throws(ModuleException::class) private fun getJsonResponse(response: String, debugMessage: String): JSONObject - ThrowsCount:Weather2.kt$Weather2.Companion$@JvmStatic @Throws(ModuleException::class) fun getWeather(query: String, apiKey: String?): List<Message> - ThrowsCount:WolframAlpha.kt$WolframAlpha.Companion$@JvmStatic @Throws(ModuleException::class) fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String - TooGenericExceptionCaught:ChatGpt2.kt$ChatGpt2.Companion$e: Exception - TooGenericExceptionCaught:Gemini.kt$Gemini.Companion$e: Exception - TooGenericExceptionCaught:Gemini2.kt$Gemini2.Companion$e: Exception - TooGenericExceptionCaught:StockQuote.kt$StockQuote.Companion$e: NullPointerException - TooGenericExceptionCaught:Weather2.kt$Weather2.Companion$e: NullPointerException - TooManyFunctions:EntryLink.kt$EntryLink : Serializable - TooManyFunctions:Mobibot.kt$Mobibot : ListenerAdapter - TooManyFunctions:Tell.kt$Tell : AbstractCommand - UtilityClassWithPublicConstructor:LocalProperties.kt$LocalProperties - WildcardImport:AddonsTest.kt$import net.thauvin.erik.mobibot.modules.* - WildcardImport:EntryLinkTest.kt$import assertk.assertions.* - WildcardImport:FeedMgrTest.kt$import assertk.assertions.* - WildcardImport:FeedReaderTest.kt$import assertk.assertions.* - WildcardImport:FeedsManager.kt$import com.rometools.rome.feed.synd.* - WildcardImport:Gemini2Test.kt$import assertk.assertions.* - WildcardImport:GeminiTest.kt$import assertk.assertions.* - WildcardImport:GoogleSearchTest.kt$import assertk.assertions.* - WildcardImport:JokeTest.kt$import assertk.assertions.* - WildcardImport:Mobibot.kt$import java.io.* - WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.commands.* - WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.commands.links.* - WildcardImport:Mobibot.kt$import net.thauvin.erik.mobibot.modules.* - WildcardImport:Mobibot.kt$import org.pircbotx.hooks.events.* - WildcardImport:ModuleExceptionTest.kt$import assertk.assertions.* - WildcardImport:SeenTest.kt$import assertk.assertions.* - WildcardImport:StockQuoteTest.kt$import assertk.assertions.* - WildcardImport:TellMessagesMgrTest.kt$import assertk.assertions.* - WildcardImport:Utils.kt$import java.io.* - WildcardImport:Weather2Test.kt$import assertk.assertions.* - - diff --git a/deploy.fish b/deploy.fish deleted file mode 100755 index d69ee4e..0000000 --- a/deploy.fish +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env fish - -./bld clean jar deploy -if test $status -eq 0 - echo "cd /home/mobibot/mobitopia/mobibot -lcd deploy -put *.jar -cd lib -rm *.jar -put lib/*.jar" | sftp nix4 -end diff --git a/lib/EXML.jar b/lib/EXML.jar new file mode 100644 index 0000000..d03257d Binary files /dev/null and b/lib/EXML.jar differ diff --git a/lib/bld/bld-wrapper.jar b/lib/bld/bld-wrapper.jar deleted file mode 100644 index 73cde27..0000000 Binary files a/lib/bld/bld-wrapper.jar and /dev/null differ diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties deleted file mode 100644 index 8b96558..0000000 --- a/lib/bld/bld-wrapper.properties +++ /dev/null @@ -1,10 +0,0 @@ -bld.downloadExtensionJavadoc=false -bld.downloadExtensionSources=true -bld.downloadLocation= -bld.extension-detekt=com.uwyn.rife2:bld-detekt:0.9.10-SNAPSHOT -bld.extension-gv=com.uwyn.rife2:bld-generated-version:1.0.1 -bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10 -bld.extension-kotlin=com.uwyn.rife2:bld-kotlin:1.1.0-SNAPSHOT -bld.repositories=MAVEN_LOCAL,MAVEN_CENTRAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES -bld.sourceDirectories= -bld.version=2.2.1 diff --git a/lib/commons-httpclient-2.0-final.jar b/lib/commons-httpclient-2.0-final.jar new file mode 100644 index 0000000..8bd4a24 Binary files /dev/null and b/lib/commons-httpclient-2.0-final.jar differ diff --git a/lib/commons-net-1.1.0.jar b/lib/commons-net-1.1.0.jar new file mode 100644 index 0000000..1b09d25 Binary files /dev/null and b/lib/commons-net-1.1.0.jar differ diff --git a/lib/fetchrss.jar b/lib/fetchrss.jar new file mode 100644 index 0000000..75b4830 Binary files /dev/null and b/lib/fetchrss.jar differ diff --git a/lib/jdom.jar b/lib/jdom.jar new file mode 100644 index 0000000..35850af Binary files /dev/null and b/lib/jdom.jar differ diff --git a/lib/jweather-0.2.3.jar b/lib/jweather-0.2.3.jar new file mode 100644 index 0000000..ec97509 Binary files /dev/null and b/lib/jweather-0.2.3.jar differ diff --git a/lib/rsslibj.jar b/lib/rsslibj.jar new file mode 100644 index 0000000..53c784b Binary files /dev/null and b/lib/rsslibj.jar differ diff --git a/licenses/Apache License.txt b/licenses/Apache License.txt deleted file mode 100644 index 261eeb9..0000000 --- a/licenses/Apache License.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/licenses/EXML-license.txt b/licenses/EXML-license.txt new file mode 100644 index 0000000..9c34118 --- /dev/null +++ b/licenses/EXML-license.txt @@ -0,0 +1,57 @@ +TERMS AND CONDITIONS FOR ELECTRIC XML + Please read this license agreement carefully. Your use of Electric XML or any +related documentation indicates your acceptance of the following terms and +conditions. If you do not agree to these terms and conditions, you may not +install or use Electric XML. The term Electric XML refers to both the basic +Electric XML software and Electric XML+. +1. Ownership and License. Electric XML is owned by The Mind Electric and is +copyrighted and licensed, not sold. The Mind Electric grants you a +non-exclusive, non-transferable license to use, modify and distribute Electric +XML in both binary and source form as long as all of the following conditions +are met: + You are not bundling Electric XML or a derivative of it as part of a software + development environment such as JBuilder, WebGain or VisualAge. Note that this + restriction is targeted at IDE vendors, and does not prevent developers from + loading Electric XML into an IDE and using it during everyday development. + You are not integrating Electric XML or a derivative of it into a distributed + computing infrastructure or database platform such as WebLogic, Apache SOAP, + WebSphere, Oracle application server, or HP e-speak. Note that this + restriction is targeted at software infrastructure vendors, and does not + prevent developers from using and bundling Electric XML with applications that + run on these platforms. + You are not integrating Electric XML or a derivative of it into an alternative + to Electric XML such as Xerces or JDOM. + You must not remove any of the copyright information from the Electric XML + source code or documentation. +If you cannot meet all of these conditions, please contact us to arrange a +special custom license. +2. Term and Termination +This Agreement is effective until terminated. You may terminate this Agreement +at any time by destroying all copies of Electric XML. This Agreement will +terminate immediately without notice from The Mind Electric if you fail to +comply with any provision of this Agreement. Upon termination, you must destroy +all copies of Electric XML. +3. Warranty Disclaimer and Limitation of Liability +The Mind Electric licenses the Software to you on an "as is" basis, without +warranty of any kind. The Mind Electric hereby expressly disclaims all +warranties or conditions, either express or implied, including, but not limited +to, the implied warranties or conditions of merchantability and fitness for a +particular purpose. You are solely responsible for determining the +appropriateness of using Electric XML and assume all risks associated with the +use of it, including but not limited to the risks of program errors, damage to +or loss of data, programs or equipment, and unavailability or interruption of +operations. Some jurisdictions do not allow for the exclusion or limitation of +implied warranties, so the above limitations or exclusions may not apply to you. +The Mind Electric will not be liable for any direct damages or for any special, +incidental, or indirect damages or for any economic consequential damages +(including lost profits or savings), even if The Mind Electric has been advised +of the possibility of such damages. The Mind Electric will not be liable for the +loss of, or damage to, your records or data, or any damages claimed by you based +on a third party claim. Some jurisdictions do not allow for the exclusion or +limitation of incidental or consequential damages, so the above limitations or +exclusions may not apply to you. +4. General +This Agreement is governed by the laws of the State of Texas. This Agreement is +the only understanding and agreement we have regarding your use of Electric XML. +It supersedes all other communications, understandings or agreements we may have +had prior to this Agreement. \ No newline at end of file diff --git a/licenses/JDOM License.txt b/licenses/JDOM License.txt deleted file mode 100644 index 660cedb..0000000 --- a/licenses/JDOM License.txt +++ /dev/null @@ -1,53 +0,0 @@ -/*-- - - Copyright (C) 2000-2012 Jason Hunter & Brett McLaughlin. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions, and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions, and the disclaimer that follows - these conditions in the documentation and/or other materials - provided with the distribution. - - 3. The name "JDOM" must not be used to endorse or promote products - derived from this software without prior written permission. For - written permission, please contact . - - 4. Products derived from this software may not be called "JDOM", nor - may "JDOM" appear in their name, without prior written permission - from the JDOM Project Management . - - In addition, we request (but do not require) that you include in the - end-user documentation provided with the redistribution and/or in the - software itself an acknowledgement equivalent to the following: - "This product includes software developed by the - JDOM Project (http://www.jdom.org/)." - Alternatively, the acknowledgment may be graphical using the logos - available at http://www.jdom.org/images/logos. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JDOM AUTHORS OR THE PROJECT - 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. - - This software consists of voluntary contributions made by many - individuals on behalf of the JDOM Project and was originally - created by Jason Hunter and - Brett McLaughlin . For more information - on the JDOM Project, please see . - - */ diff --git a/licenses/JSON License.txt b/licenses/JSON License.txt deleted file mode 100644 index 4933197..0000000 --- a/licenses/JSON License.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/licenses/LICENSE.txt b/licenses/LICENSE.txt deleted file mode 100644 index 085f7c7..0000000 --- a/licenses/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2004-2022, 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. diff --git a/licenses/OWM JAPIs License.txt b/licenses/OWM JAPIs License.txt deleted file mode 100644 index cf80d7d..0000000 --- a/licenses/OWM JAPIs License.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2013- Ashutosh Kumar Singh - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/licenses/PircBotX.txt b/licenses/PircBotX.txt deleted file mode 100644 index 9fa1ca4..0000000 --- a/licenses/PircBotX.txt +++ /dev/null @@ -1,13 +0,0 @@ -Copyright (C) 2010-2014 Leon Blakey - -PircBotX is free software: you can redistribute it and/or modify it under the -terms of the GNU General Public License as published by the Free Software -Foundation, either version 3 of the License, or (at your option) any later -version. - -PircBotX 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 General Public License for more details. - -You should have received a copy of the GNU General Public License along with -PircBotX. If not, see . \ No newline at end of file diff --git a/licenses/RSSJLib License.txt b/licenses/RSSJLib License.txt new file mode 100644 index 0000000..b475844 --- /dev/null +++ b/licenses/RSSJLib License.txt @@ -0,0 +1,83 @@ +Apache Software License +Version 1.1 + +Copyright (c) 2000 The Apache Software Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. 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. + +3. The end-user documentation included with the redistribution, if any, must +include the following acknowledgment: + +"This product includes software developed by the Apache Software Foundation +(http://www.apache.org/)." + +Alternately, this acknowledgment may appear in the software itself, if and +wherever such third-party acknowledgments normally appear. + +4. The names "Apache" and "Apache Software Foundation" must not be used to +endorse or promote products derived from this software without prior written +permission. For written permission, please contact apache@apache.org. + +5. Products derived from this software may not be called "Apache", nor may +"Apache" appear in their name, without prior written permission of the Apache +Software Foundation. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 APACHE +SOFTWARE FOUNDATION OR ITS 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. + + + +-------------------------------------------------------------------------------- + + +This software consists of voluntary contributions made by many individuals on +behalf of the Apache Software Foundation. For more information on the Apache +Software Foundation, please see . + +Portions of this software are based upon public domain software originally +written at the National Center for Supercomputing Applications, University of +Illinois, Urbana-Champaign. + +Electric XML is owned by The Mind Electric and is copyrighted and licensed, not +sold. The Mind Electric grants you a non-exclusive, non-transferable license to +use, modify and distribute Electric XML in both binary and source form as long +as all of the following conditions are met: + +You are not bundling Electric XML or a derivative of it as part of a software +development environment such as JBuilder, WebGain or VisualAge. Note that this +restriction is targeted at IDE vendors, and does not prevent developers from +loading Electric XML into an IDE and using it during everyday development. + + +You are not integrating Electric XML or a derivative of it into a distributed +computing infrastructure or database platform such as WebLogic, Apache SOAP, +WebSphere, Oracle application server, or HP e-speak. Note that this restriction +is targeted at software infrastructure vendors, and does not prevent developers +from using and bundling Electric XML with applications that run on these +platforms. + + +You are not integrating Electric XML or a derivative of it into an alternative +to Electric XML such as Xerces or JDOM. + + +You must not remove any of the copyright information from the Electric XML +source code or documentation. + + diff --git a/licenses/SLF4J License.txt b/licenses/SLF4J License.txt deleted file mode 100644 index 744377c..0000000 --- a/licenses/SLF4J License.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2004-2017 QOS.ch -All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/fetchrss License.txt b/licenses/fetchrss License.txt new file mode 100644 index 0000000..e22776b --- /dev/null +++ b/licenses/fetchrss License.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! \ No newline at end of file diff --git a/licenses/jsoup License.txt b/licenses/jsoup License.txt deleted file mode 100644 index 31b785d..0000000 --- a/licenses/jsoup License.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2009-2022 Jonathan Hedley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 58768ef..0000000 --- a/pom.xml +++ /dev/null @@ -1,199 +0,0 @@ - - - 4.0.0 - net.thauvin.erik.mobibot - mobibot - 0.8.0-rc+20250424113056 - mobibot - - - - - com.github.pircbotx - pircbotx - 2.3.1 - compile - - - org.apache.commons - commons-lang3 - 3.17.0 - compile - - - org.apache.commons - commons-text - 1.13.1 - compile - - - commons-codec - commons-codec - 1.18.0 - compile - - - commons-net - commons-net - 3.11.1 - compile - - - com.google.code.gson - gson - 2.13.1 - compile - - - com.google.guava - guava - 33.2.1-jre - compile - - - org.jetbrains.kotlin - kotlin-stdlib - 2.1.20 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-common - 2.1.20 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-jdk7 - 2.1.20 - compile - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 2.1.20 - compile - - - org.jetbrains.kotlinx - kotlinx-coroutines-core - 1.10.2 - compile - - - org.jetbrains.kotlinx - kotlinx-cli-jvm - 0.3.6 - compile - - - org.slf4j - slf4j-api - 2.0.17 - compile - - - org.apache.logging.log4j - log4j-api - 2.24.3 - compile - - - org.apache.logging.log4j - log4j-core - 2.24.3 - compile - - - org.apache.logging.log4j - log4j-slf4j2-impl - 2.24.3 - compile - - - dev.langchain4j - langchain4j-open-ai - 0.36.2 - compile - - - dev.langchain4j - langchain4j-google-ai-gemini - 0.36.2 - compile - - - dev.langchain4j - langchain4j-core - 0.36.2 - compile - - - dev.langchain4j - langchain4j - 0.36.2 - compile - - - com.rometools - rome - 2.1.0 - compile - - - com.squareup.okhttp3 - okhttp - 4.12.0 - compile - - - net.aksingh - owm-japis - 2.5.3.0 - compile - - - net.objecthunter - exp4j - 0.4.8 - compile - - - org.json - json - 20250107 - compile - - - org.jsoup - jsoup - 1.19.1 - compile - - - net.thauvin.erik - cryptoprice - 1.0.3-SNAPSHOT - compile - - - net.thauvin.erik - jokeapi - 1.0.1-SNAPSHOT - compile - - - net.thauvin.erik - pinboard-poster - 1.2.1-SNAPSHOT - compile - - - net.thauvin.erik.urlencoder - urlencoder-lib-jvm - 1.6.0 - compile - - - diff --git a/properties/log4j2.xml b/properties/log4j2.xml deleted file mode 100644 index 0aa95bf..0000000 --- a/properties/log4j2.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/properties/mobibot.properties b/properties/mobibot.properties deleted file mode 100644 index fd7b104..0000000 --- a/properties/mobibot.properties +++ /dev/null @@ -1,86 +0,0 @@ -channel=#mobitopia -server=irc.libera.chat -#port=6667 -login=mobibot -nick=mobibot -#realname=mobibot - -# Die command password, if any -#die=changeme - -# NickServ password -ident=changeme -#ident-nick=nickserv -#ident-msg=IDENTIFY changepwd - -logs=./logs -ignore=chanserv,nickserv -tags=mobile mobitopia -tags-keywords=android ios apple google - -feed=http://www.mobitopia.org/rss.xml -backlogs=http://www.mobitopia.org/mobibot/logs - -tell-max-days=5 -tell-max-size=50 - -#disabled-commands=die, ignore -disabled-modules=mastodon - -# -# API Token for: https://pinboard.in/settings/password -# -#pinboard-api-token=user\:TOKEN - -# -# Create a Mastodon application access token at: https//SERVER_INSTANCE/settings/applications -# Make sure the 'write:statuses' scope is enabled. -# -#mastodon-access-token= -#mastodon-instance=mastodon.social - -# Mastodon handle to receive channel join/leave notifications -#mastodon-handle=@mobitopia - -# Automatically post links to Mastodon -#mastodon-auto-post=true - -# -# Get Exchange Rate API key from: https://www.exchangerate-api.com/ -# -#exchangerate-api-key= - -# -# Create custom search engine at: https://programmablesearchengine.google.com/ -# and get API key from: https://console.cloud.google.com/apis -# -#google-api= -#google-cse-cx= - -# -# Get OpenWeatherMap API key from: https://openweathermap.org/api -# -#owm-api-key= - -# -# Get Alpha Vantage Stock Quote API key from: https://www.alphavantage.co/support/#api-key -# -#alphavantage-api-key= - -# -# Get Wolfram Alpha AppID from: https://developer.wolframalpha.com/portal/ -# -#wolfram-appid= -#wolfram-units=imperial - -# -# Get ChatGPT/OpenAI API key from: https://platform.openai.com/api-keys -# -#chatgpt-api-key= -#chatgpt-max-tokens=1024 - -# -# Get Google Gemini API key from https://ai.google.dev/gemini-api/docs/api-key -# -#gemini-api-key= -#gemini-max-tokens=1024 diff --git a/release_info.txt b/release_info.txt deleted file mode 100644 index d2c33ac..0000000 --- a/release_info.txt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is automatically generated - * Do not modify! -- ALL CHANGES WILL BE ERASED! - */ - -package {{v packageName/}} - -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneId - -/** - * Provides release information. - */ -object {{v className/}} { - const val PROJECT = "{{v project/}}" - const val VERSION = "{{v version/}}" - - @JvmField - @Suppress("MagicNumber") - val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli({{v epoch/}}L), ZoneId.systemDefault() - ) - - const val WEBSITE = "https://mobitopia.org/mobibot/" - const val AUTHOR = "Erik C. Thauvin" - const val AUTHOR_URL = "https://erik.thauvin.net/" -} diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index 85d8fce..0000000 --- a/sonar-project.properties +++ /dev/null @@ -1,7 +0,0 @@ -sonar.organization=ethauvin-github -sonar.projectKey=ethauvin_mobibot -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml -sonar.sources=src/main/kotlin/ -sonar.tests=src/test/kotlin/ -sonar.java.binaries=build/main,build/test -sonar.java.libraries=lib/compile/*.jar diff --git a/src/bld/java/net/thauvin/erik/MobibotBuild.java b/src/bld/java/net/thauvin/erik/MobibotBuild.java deleted file mode 100644 index 08367ef..0000000 --- a/src/bld/java/net/thauvin/erik/MobibotBuild.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * MobibotBuild.java - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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; - -import rife.bld.BuildCommand; -import rife.bld.Project; -import rife.bld.dependencies.Repository; -import rife.bld.extension.CompileKotlinOperation; -import rife.bld.extension.DetektOperation; -import rife.bld.extension.GeneratedVersionOperation; -import rife.bld.extension.JacocoReportOperation; -import rife.bld.extension.kotlin.CompileOptions; -import rife.bld.operations.exceptions.ExitStatusException; -import rife.bld.publish.PomBuilder; -import rife.tools.FileUtils; -import rife.tools.exceptions.FileUtilsErrorException; - -import java.io.File; -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.jar.Attributes; -import java.util.logging.ConsoleHandler; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static rife.bld.dependencies.Repository.*; -import static rife.bld.dependencies.Scope.compile; -import static rife.bld.dependencies.Scope.test; - -public class MobibotBuild extends Project { - private static final String DETEKT_BASELINE = "config/detekt/baseline.xml"; - final File srcMainKotlin = new File(srcMainDirectory(), "kotlin"); - - public MobibotBuild() { - pkg = "net.thauvin.erik.mobibot"; - name = "mobibot"; - version = version(0, 8, 0, "rc+" + - DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now())); - - mainClass = pkg + ".Mobibot"; - - javaRelease = 17; - downloadSources = true; - autoDownloadPurge = true; - repositories = List.of( - MAVEN_LOCAL, - MAVEN_CENTRAL, - new Repository("https://jitpack.io"), - SONATYPE_SNAPSHOTS_LEGACY); - - var log4j = version(2, 24, 3); - var kotlin = version(2, 1, 20); - var langchain = version(0, 36, 2); - scope(compile) - // PircBotX - .include(dependency("com.github.pircbotx", "pircbotx", "2.3.1")) - // Commons (mostly for PircBotX) - .include(dependency("org.apache.commons", "commons-lang3", "3.17.0")) - .include(dependency("org.apache.commons", "commons-text", "1.13.1")) - .include(dependency("commons-codec", "commons-codec", "1.18.0")) - .include(dependency("commons-net", "commons-net", "3.11.1")) - // Google - .include(dependency("com.google.code.gson", "gson", "2.13.1")) - .include(dependency("com.google.guava", "guava", "33.2.1-jre")) - // Kotlin - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-common", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk7", kotlin)) - .include(dependency("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", kotlin)) - .include(dependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core", "1.10.2")) - .include(dependency("org.jetbrains.kotlinx", "kotlinx-cli-jvm", "0.3.6")) - // Logging - .include(dependency("org.slf4j", "slf4j-api", "2.0.17")) - .include(dependency("org.apache.logging.log4j", "log4j-api", log4j)) - .include(dependency("org.apache.logging.log4j", "log4j-core", log4j)) - .include(dependency("org.apache.logging.log4j", "log4j-slf4j2-impl", log4j)) - // LangChain4J - .include(dependency("dev.langchain4j", "langchain4j-open-ai", langchain)) - .include(dependency("dev.langchain4j", "langchain4j-google-ai-gemini", langchain)) - .include(dependency("dev.langchain4j", "langchain4j-core", langchain)) - .include(dependency("dev.langchain4j", "langchain4j", langchain)) - // Misc. - .include(dependency("com.rometools", "rome", "2.1.0")) - .include(dependency("com.squareup.okhttp3", "okhttp", "4.12.0")) - .include(dependency("net.aksingh", "owm-japis", "2.5.3.0")) - .include(dependency("net.objecthunter", "exp4j", "0.4.8")) - .include(dependency("org.json", "json", "20250107")) - .include(dependency("org.jsoup", "jsoup", "1.19.1")) - // Thauvin - .include(dependency("net.thauvin.erik", "cryptoprice", "1.0.3-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "jokeapi", "1.0.1-SNAPSHOT")) - .include(dependency("net.thauvin.erik", "pinboard-poster", "1.2.1-SNAPSHOT")) - .include(dependency("net.thauvin.erik.urlencoder", "urlencoder-lib-jvm", "1.6.0")); - scope(test) - .include(dependency("com.willowtreeapps.assertk", "assertk-jvm", version(0, 28, 1))) - .include(dependency("org.jetbrains.kotlin", "kotlin-test-junit5", kotlin)) - .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2))) - .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2))) - .include(dependency("org.junit.platform", "junit-platform-launcher", version(1, 12, 2))); - - List jars = new ArrayList<>(); - runtimeClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); - compileClasspathJars().forEach(f -> jars.add("./lib/" + f.getName())); - jarOperation() - .manifestAttribute(Attributes.Name.MAIN_CLASS, mainClass()) - .manifestAttribute(Attributes.Name.CLASS_PATH, ". " + String.join(" ", jars)); - - jarSourcesOperation().sourceDirectories(srcMainKotlin); - } - - public static void main(String[] args) { - var level = Level.ALL; - var logger = Logger.getLogger("rife.bld.extension"); - var consoleHandler = new ConsoleHandler(); - - consoleHandler.setLevel(level); - logger.addHandler(consoleHandler); - logger.setLevel(level); - logger.setUseParentHandlers(false); - - new MobibotBuild().start(args); - } - - @Override - public void clean() throws Exception { - var deploy = new File("deploy"); - if (deploy.exists()) { - FileUtils.deleteDirectory(deploy); - } - super.clean(); - } - - @BuildCommand(summary = "Compiles the Kotlin project") - @Override - public void compile() throws Exception { - releaseInfo(); - new CompileKotlinOperation() - .compileOptions(new CompileOptions().progressive(true).verbose(true)) - .fromProject(this) - .execute(); - } - - @Override - public void updates() throws Exception { - super.updates(); - pomRoot(); - } - - @BuildCommand(summary = "Copies all needed files to the deploy directory") - public void deploy() throws FileUtilsErrorException { - var deploy = new File("deploy"); - var lib = new File(deploy, "lib"); - var ignore = lib.mkdirs(); - FileUtils.copyDirectory(new File("properties"), deploy); - for (var jar : compileClasspathJars()) { - FileUtils.copy(jar, new File(lib, jar.getName())); - } - for (var jar : runtimeClasspathJars()) { - FileUtils.copy(jar, new File(lib, jar.getName())); - } - FileUtils.copy(new File(buildDistDirectory(), jarFileName()), new File(deploy, "mobibot.jar")); - } - - @BuildCommand(summary = "Checks source with Detekt") - public void detekt() throws ExitStatusException, IOException, InterruptedException { - new DetektOperation() - .fromProject(this) - .baseline(DETEKT_BASELINE) - .execute(); - } - - @BuildCommand(value = "detekt-baseline", summary = "Creates the Detekt baseline") - public void detektBaseline() throws ExitStatusException, IOException, InterruptedException { - new DetektOperation() - .fromProject(this) - .baseline(DETEKT_BASELINE) - .createBaseline(true) - .execute(); - } - - @BuildCommand(summary = "Generates JaCoCo Reports") - public void jacoco() throws Exception { - new JacocoReportOperation() - .fromProject(this) - .sourceFiles(srcMainKotlin) - .execute(); - } - - @BuildCommand(value = "pom-root", summary = "Generates the POM file in the root directory") - public void pomRoot() throws FileUtilsErrorException { - PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(), - new File(workDirectory, "pom.xml")); - } - - @BuildCommand(value = "release-info", summary = "Generates the ReleaseInfo class") - public void releaseInfo() throws Exception { - new GeneratedVersionOperation() - .fromProject(this) - .classTemplate(new File(workDirectory(), "release-info.txt")) - .className("ReleaseInfo") - .packageName(pkg) - .directory(srcMainKotlin) - .extension(".kt") - .execute(); - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt deleted file mode 100644 index ed34897..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Addons.kt +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Addons.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import net.thauvin.erik.mobibot.Utils.notContains -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.modules.AbstractModule -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Modules and Commands addons. - */ -class Addons(private val props: Properties) { - private val logger: Logger = LoggerFactory.getLogger(Addons::class.java) - private val disabledModules = props.getProperty("disabled-modules", "").split(LinksManager.TAG_MATCH) - private val disableCommands = props.getProperty("disabled-commands", "").split(LinksManager.TAG_MATCH) - - val commands: MutableList = mutableListOf() - val modules: MutableList = mutableListOf() - val names = Names - - /** - * Add a module with properties. - */ - fun add(module: AbstractModule): Boolean { - var enabled = false - with(module) { - if (disabledModules.notContains(name, true)) { - if (hasProperties()) { - propertyKeys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - - if (isEnabled) { - modules.add(this) - names.modules.add(name) - names.commands.addAll(commands) - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Module $name is disabled.") - } - names.disabledModules.add(name) - } - } else { - names.disabledModules.add(name) - } - } - return enabled - } - - /** - * Add a command with properties. - */ - fun add(command: AbstractCommand): Boolean { - var enabled = false - with(command) { - if (disableCommands.notContains(name, true)) { - if (properties.isNotEmpty()) { - properties.keys.forEach { - setProperty(it, props.getProperty(it, "")) - } - } - if (isEnabled()) { - commands.add(this) - if (isVisible) { - if (isOpOnly) { - names.ops.add(name) - } else { - names.commands.add(name) - } - } - enabled = true - } else { - if (logger.isDebugEnabled) { - logger.debug("Command $name is disabled.") - } - names.disabledCommands.add(name) - } - } else { - names.disabledCommands.add(name) - } - } - return enabled - } - - /** - * Execute a command or module. - */ - fun exec(channel: String, cmd: String, args: String, event: GenericMessageEvent): Boolean { - val cmds = if (event is PrivateMessageEvent) commands else commands.filter { it.isPublic } - for (command in cmds) { - if (command.name.startsWith(cmd)) { - command.commandResponse(channel, args, event) - return true - } - } - val mods = if (event is PrivateMessageEvent) modules.filter { it.isPrivateMsgEnabled } else modules - for (module in mods) { - if (module.commands.contains(cmd)) { - module.commandResponse(channel, cmd, args, event) - return true - } - } - return false - } - - /** - * Match a command. - */ - fun match(channel: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.matches(event.message)) { - command.commandResponse(channel, event.message, event) - return true - } - } - return false - } - - /** - * Commands and Modules help. - */ - fun help(channel: String, topic: String, event: GenericMessageEvent): Boolean { - for (command in commands) { - if (command.isVisible && command.name.startsWith(topic)) { - return command.helpResponse(channel, topic, event) - } - } - for (module in modules) { - if (module.commands.contains(topic)) { - return module.helpResponse(event) - } - } - return false - } - - /** - * Holds commands and modules names. - */ - object Names { - val modules: MutableList = mutableListOf() - val disabledModules: MutableList = mutableListOf() - val commands: MutableList = mutableListOf() - val disabledCommands: MutableList = mutableListOf() - val ops: MutableList = mutableListOf() - - fun sort() { - modules.sort() - disabledModules.sort() - commands.sort() - disabledCommands.sort() - ops.sort() - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt deleted file mode 100644 index 0dea8d5..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Constants.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Constants.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -/** - * The `Constants`. - */ -object Constants { - /** - * The connect/read timeout in ms. - */ - const val CONNECT_TIMEOUT = 5000 - - /** - * Debug command line argument. - */ - const val DEBUG_ARG = "debug" - - /** - * Default IRC Port. - */ - const val DEFAULT_PORT = 6667 - - /** - * Default IRC Server. - */ - const val DEFAULT_SERVER = "irc.libera.chat" - - /** - * CLI command for usage. - */ - const val CLI_CMD = "java -jar ${ReleaseInfo.PROJECT}.jar" - - /** - * User-Agent - */ - const val USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:136.0) Gecko/20100101 Firefox/136.0" - - /** - * The help command. - */ - const val HELP_CMD = "help" - - /** - * The link command. - */ - const val LINK_CMD = "L" - - /** - * The empty title string. - */ - const val NO_TITLE = "No Title" - - /** - * Properties command line argument. - */ - const val PROPS_ARG = "properties" - - /** - * The tag command - */ - const val TAG_CMD = "T" - - /** - * The timer delay in minutes. - */ - const val TIMER_DELAY = 10L - - /** - * Properties version line argument. - */ - const val VERSION_ARG = "version" -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt b/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt deleted file mode 100644 index 3ab8d1f..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/FeedReader.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * FeedReader.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import com.rometools.rome.io.FeedException -import com.rometools.rome.io.SyndFeedInput -import com.rometools.rome.io.XmlReader -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.entries.FeedsManager -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * Reads an RSS feed. - */ -class FeedReader(private val url: String, val event: GenericMessageEvent) : Runnable { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - /** - * Fetches the Feed's items. - */ - override fun run() { - try { - readFeed(url).forEach { - event.sendMessage("", it) - } - } catch (e: FeedException) { - if (logger.isWarnEnabled) logger.warn("Unable to parse the feed at $url", e) - event.sendMessage("An error has occurred while parsing the feed: ${e.message}") - } catch (e: IOException) { - if (logger.isWarnEnabled) logger.warn("Unable to fetch the feed at $url", e) - event.sendMessage("An IO error has occurred while fetching the feed: ${e.message}") - } - } - - companion object { - @JvmStatic - @Throws(FeedException::class, IOException::class) - fun readFeed(url: String, maxItems: Int = 5): List { - val messages = mutableListOf() - val input = SyndFeedInput() - XmlReader(URL(url).openStream()).use { reader -> - val feed = input.build(reader) - val items = feed.entries - if (items.isEmpty()) { - messages.add(NoticeMessage("There is currently nothing to view.")) - } else { - items.take(maxItems).forEach { - messages.add(NoticeMessage(it.title)) - messages.add(NoticeMessage(helpFormat(it.link.green(), false))) - } - } - } - return messages - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt deleted file mode 100644 index 691a339..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Mobibot.kt +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Mobibot.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import kotlinx.cli.ArgParser -import kotlinx.cli.ArgType -import kotlinx.cli.default -import net.thauvin.erik.mobibot.Utils.appendIfMissing -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.commands.* -import net.thauvin.erik.mobibot.commands.Recap.Companion.storeRecap -import net.thauvin.erik.mobibot.commands.links.* -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import net.thauvin.erik.mobibot.modules.* -import org.pircbotx.Configuration -import org.pircbotx.PircBotX -import org.pircbotx.hooks.ListenerAdapter -import org.pircbotx.hooks.events.* -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.* -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import java.util.regex.Pattern -import kotlin.system.exitProcess - -class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Properties) : ListenerAdapter() { - // The bot configuration. - private val config: Configuration - - // Commands and Modules - private val addons: Addons - - // Seen command - private val seen: Seen - - // Tell command - private val tell: Tell - - /** Logger. */ - val logger: Logger = LoggerFactory.getLogger(Mobibot::class.java) - - /** - * Connects to the server and joins the channel. - */ - fun connect() { - PircBotX(config).startBot() - } - - /** - * Responds with the default help. - */ - private fun helpDefault(event: GenericMessageEvent) { - event.sendMessage("Type a URL on $channel to post it.") - event.sendMessage("For more information on a specific command, type:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c ${Constants.HELP_CMD} ", event.bot().nick, event is PrivateMessageEvent) - ) - ) - event.sendMessage("The commands are:") - event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) - if (event.isChannelOp(channel)) { - if (addons.names.disabledCommands.isNotEmpty()) { - event.sendMessage("The disabled commands are:") - event.sendList(addons.names.disabledCommands, 8, isBold = false, isIndent = true) - } - event.sendMessage("The op commands are:") - event.sendList(addons.names.ops, 8, isBold = true, isIndent = true) - } - } - - /** - * Responds with the default, commands or modules help. - */ - private fun helpResponse(event: GenericMessageEvent, topic: String) { - if (topic.isBlank() || !addons.help(channel, topic.lowercase().trim(), event)) { - helpDefault(event) - } - } - - override fun onAction(event: ActionEvent?) { - event?.channel?.let { - if (channel == it.name) { - event.user?.let { user -> - storeRecap(user.nick, event.action, true) - } - } - } - } - - override fun onDisconnect(event: DisconnectEvent?) { - event?.let { - with(event.getBot()) { - LinksManager.socialManager.notification("$nick disconnected from $serverHostname") - seen.add(userChannelDao.getChannel(channel).users) - } - } - LinksManager.socialManager.shutdown() - } - - override fun onPrivateMessage(event: PrivateMessageEvent?) { - event?.user?.let { user -> - if (logger.isTraceEnabled) logger.trace("<<< ${user.nick}: ${event.message}") - val cmds = event.message.trim().split(" ".toRegex(), 2) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - if (cmd.startsWith(Constants.HELP_CMD)) { // help - helpResponse(event, args) - } else if (!addons.exec(channel, cmd, args, event)) { // Execute command or module - helpDefault(event) - } - } - } - - override fun onJoin(event: JoinEvent?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has joined ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - tell.send(event) - seen.add(user.nick) - } - } - } - } - - override fun onMessage(event: MessageEvent?) { - event?.user?.let { user -> - tell.send(event) - if (event.message.matches("(?i)${Pattern.quote(event.bot().nick)}:.*".toRegex())) { // mobibot: - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") - val cmds = event.message.substring(event.bot().nick.length + 1).trim().split(" ".toRegex(), 2) - val cmd = cmds[0].lowercase() - val args = cmds.lastOrEmpty().trim() - if (cmd.startsWith(Constants.HELP_CMD)) { // mobibot: help - helpResponse(event, args) - } else { - // Execute module or command - addons.exec(channel, cmd, args, event) - } - } else if (addons.match(channel, event)) { // Links, e.g.: https://www.example.com/ or L1: , etc. - if (logger.isTraceEnabled) logger.trace(">>> ${user.nick}: ${event.message}") - } - storeRecap(user.nick, event.message, false) - seen.add(user.nick) - } - } - - override fun onNickChange(event: NickChangeEvent?) { - event?.let { - tell.send(event) - if (!it.oldNick.equals(it.newNick, true)) { - seen.add(it.oldNick) - } - seen.add(it.newNick) - } - } - - override fun onPart(event: PartEvent?) { - event?.user?.let { user -> - with(event.getBot()) { - if (user.nick == nick) { - LinksManager.socialManager.notification( - "$nick has left ${event.channel.name} on $serverHostname" - ) - seen.add(userChannelDao.getChannel(channel).users) - } else { - seen.add(user.nick) - } - } - } - } - - override fun onQuit(event: QuitEvent?) { - event?.user?.let { user -> - seen.add(user.nick) - } - } - - companion object { - @JvmStatic - @Throws(Exception::class) - fun main(args: Array) { - // Set up the command line options - val parser = ArgParser(Constants.CLI_CMD) - val debug by parser.option( - ArgType.Boolean, - Constants.DEBUG_ARG, - Constants.DEBUG_ARG.substring(0, 1), - "Print debug & logging data directly to the console" - ).default(false) - val property by parser.option( - ArgType.String, - Constants.PROPS_ARG, - Constants.PROPS_ARG.substring(0, 1), - "Use alternate properties file" - ).default("./${ReleaseInfo.PROJECT}.properties") - val version by parser.option( - ArgType.Boolean, - Constants.VERSION_ARG, - Constants.VERSION_ARG.substring(0, 1), - "Print version info" - ).default(false) - - // Parse the command line - parser.parse(args) - - if (version) { - // Output the version - println( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + - " (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})" - ) - println(ReleaseInfo.WEBSITE) - } else { - // Load the properties - val p = Properties() - try { - Files.newInputStream( - Paths.get(property) - ).use { fis -> - p.load(fis) - } - } catch (ignore: FileNotFoundException) { - System.err.println("Unable to find properties file.") - exitProcess(1) - } catch (ignore: IOException) { - System.err.println("Unable to open properties file.") - exitProcess(1) - } - val nickname = p.getProperty("nick", Mobibot::class.java.name.lowercase()) - val channel = p.getProperty("channel") - val logsDir = p.getProperty("logs", ".").appendIfMissing(File.separatorChar) - - // Redirect stdout and stderr - if (!debug) { - try { - val stdout = PrintStream( - BufferedOutputStream( - FileOutputStream( - logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true - ) - ), true - ) - System.setOut(stdout) - } catch (ignore: IOException) { - System.err.println("Unable to open output (stdout) log file.") - exitProcess(1) - } - try { - val stderr = PrintStream( - BufferedOutputStream( - FileOutputStream("$logsDir$nickname.err", true) - ), true - ) - System.setErr(stderr) - } catch (ignore: IOException) { - System.err.println("Unable to open error (stderr) log file.") - exitProcess(1) - } - } - - // Start the bot - Mobibot(nickname, channel, logsDir, p).connect() - } - } - } - - /** - * Initialize the bot. - */ - init { - val ircServer = p.getProperty("server", Constants.DEFAULT_SERVER) - config = Configuration.Builder().apply { - name = nickname - login = p.getProperty("login", nickname) - realName = p.getProperty("realname", nickname) - addServer( - ircServer, - p.getIntProperty("port", Constants.DEFAULT_PORT) - ) - addAutoJoinChannel(channel) - addListener(this@Mobibot) - version = "${ReleaseInfo.PROJECT} ${ReleaseInfo.VERSION}" - isAutoNickChange = true - val identPwd = p.getProperty("ident") - if (!identPwd.isNullOrBlank()) { - nickservPassword = identPwd - } - val identNick = p.getProperty("ident-nick") - if (!identNick.isNullOrBlank()) { - nickservNick = identNick - } - val identMsg = p.getProperty("ident-msg") - if (!identMsg.isNullOrBlank()) { - nickservCustomMessage = identMsg - } - isAutoReconnect = true - - //socketConnectTimeout = Constants.CONNECT_TIMEOUT - //socketTimeout = Constants.CONNECT_TIMEOUT - //messageDelay = StaticDelay(500) - }.buildConfiguration() - - // Load the current entries - with(LinksManager) { - entries.channel = channel - entries.ircServer = ircServer - entries.logsDir = logsDirPath - entries.backlogs = p.getProperty("backlogs", "") - entries.load() - - // Set up pinboard - pinboard.setApiToken(p.getProperty("pinboard-api-token", "")) - } - - addons = Addons(p) - - // Load the commands - addons.add(ChannelFeed(channel.removePrefix("#"))) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) - addons.add(Ignore()) - addons.add(LinksManager()) - addons.add(Me()) - addons.add(Modules(addons.names.modules, addons.names.disabledModules)) - addons.add(Msg()) - addons.add(Nick()) - addons.add(Posting()) - addons.add(Recap()) - addons.add(Say()) - - // Seen command - seen = Seen("${logsDirPath}${nickname}-seen.ser") - addons.add(seen) - - addons.add(Tags()) - - // Tell command - tell = Tell("${logsDirPath}${nickname}.ser") - addons.add(tell) - - addons.add(Users()) - addons.add(Versions()) - addons.add(View()) - - // Load social modules - LinksManager.socialManager.add(addons, Mastodon()) - - // Load the modules - addons.add(Calc()) - addons.add(ChatGpt2()) - addons.add(CryptoPrices()) - addons.add(CurrencyConverter()) - addons.add(Dice()) - addons.add(Gemini2()) - addons.add(GoogleSearch()) - addons.add(Info(tell, seen)) - addons.add(Joke()) - addons.add(Lookup()) - addons.add(Ping()) - addons.add(RockPaperScissors()) - addons.add(StockQuote()) - addons.add(War()) - addons.add(Weather2()) - addons.add(WolframAlpha()) - addons.add(WorldTime()) - - // Sort the addons - addons.names.sort() - } -} - diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt deleted file mode 100644 index f9076c9..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Pinboard.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Pinboard.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.pinboard.PinboardPoster -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoUnit -import java.util.* - -/** - * Handles posts to pinboard.in. - */ -class Pinboard { - private val poster = PinboardPoster() - - /** - * Adds a pin. - */ - fun addPin(ircServer: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Sets the pinboard API token. - */ - fun setApiToken(apiToken: String) { - poster.apiToken = apiToken - } - - /** - * Deletes a pin. - */ - fun deletePin(entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - poster.deletePin(entry.link) - } - - } - - /** - * Updates a pin. - */ - fun updatePin(ircServer: String, oldUrl: String, entry: EntryLink) { - if (poster.apiToken.isNotBlank()) { - with(entry) { - if (oldUrl != link) { - poster.deletePin(oldUrl) - } - poster.addPin(link, title, postedBy(ircServer), formatTags(), date.toTimestamp()) - } - } - } - - /** - * Formats a date to a UTC timestamp. - */ - private fun Date.toTimestamp(): String { - return ZonedDateTime.ofInstant( - toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() - ).format(DateTimeFormatter.ISO_INSTANT) - } - - /** - * Formats the tags for pinboard. - */ - private fun EntryLink.formatTags(): String { - return nick + formatTags(",", ",") - } - - /** - * Returns the pinboard.in extended attribution line. - */ - private fun EntryLink.postedBy(ircServer: String): String { - return "Posted by $nick on $channel ( $ircServer )" - } -} - diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt b/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt deleted file mode 100644 index 42a61aa..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/ReleaseInfo.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is automatically generated - * Do not modify! -- ALL CHANGES WILL BE ERASED! - */ - -package net.thauvin.erik.mobibot - -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneId - -/** - * Provides release information. - */ -object ReleaseInfo { - const val PROJECT = "mobibot" - const val VERSION = "0.8.0-rc+20250322004101" - - @JvmField - @Suppress("MagicNumber") - val BUILD_DATE: LocalDateTime = LocalDateTime.ofInstant( - Instant.ofEpochMilli(1742629261438L), ZoneId.systemDefault() - ) - - const val WEBSITE = "https://mobitopia.org/mobibot/" - const val AUTHOR = "Erik C. Thauvin" - const val AUTHOR_URL = "https://erik.thauvin.net/" -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt deleted file mode 100644 index 97797ef..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/Utils.kt +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Utils.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import net.thauvin.erik.urlencoder.UrlEncoderUtil -import org.jsoup.Jsoup -import org.pircbotx.Colors -import org.pircbotx.PircBotX -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import java.io.* -import java.net.HttpURLConnection -import java.net.URL -import java.nio.file.Files -import java.nio.file.Paths -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.util.* -import kotlin.io.path.exists -import kotlin.io.path.fileSize - -/** - * Miscellaneous utilities. - */ -@Suppress("TooManyFunctions") -object Utils { - private val searchFlags = arrayOf("%c", "%n") - - /** - * Prepends a prefix if not present. - */ - @JvmStatic - fun String.prefixIfMissing(prefix: Char): String { - return if (first() != prefix) { - "$prefix${this}" - } else { - this - } - } - - /** - * Appends a suffix to the end of the String if not present. - */ - @JvmStatic - fun String.appendIfMissing(suffix: Char): String { - return if (last() != suffix) { - "$this${suffix}" - } else { - this - } - } - - /** - * Makes the given int bold. - */ - @JvmStatic - fun Int.bold(): String = toString().bold() - - /** - * Makes the given long bold. - */ - @JvmStatic - fun Long.bold(): String = toString().bold() - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.bold(): String = colorize(Colors.BOLD) - - /** - * Returns the [PircBotX] instance. - */ - fun GenericMessageEvent.bot(): PircBotX { - return getBot() as PircBotX - } - - /** - * Capitalize a string. - */ - @JvmStatic - fun String.capitalise(): String = lowercase().replaceFirstChar { it.uppercase() } - - /** - * Capitalize words - */ - @JvmStatic - fun String.capitalizeWords(): String = split(" ").joinToString(" ") { it.capitalise() } - - /** - * Colorize a string. - */ - @JvmStatic - fun String?.colorize(color: String): String { - return when { - isNullOrEmpty() -> { - "" - } - - color == DEFAULT_COLOR -> { - this - } - - Colors.BOLD == color || Colors.REVERSE == color -> { - color + this + color - } - - else -> { - color + this + Colors.NORMAL - } - } - } - - /** - * Makes the given string cyan. - */ - @JvmStatic - fun String?.cyan(): String = colorize(Colors.CYAN) - - /** - * URL encodes the given string. - */ - @JvmStatic - fun String.encodeUrl(): String = UrlEncoderUtil.encode(this) - - /** - * Returns a property as an int. - */ - @JvmStatic - fun Properties.getIntProperty(key: String, defaultValue: Int): Int { - return getProperty(key)?.toIntOrDefault(defaultValue) ?: defaultValue - } - - /** - * Makes the given string green. - */ - @JvmStatic - fun String?.green(): String = colorize(Colors.DARK_GREEN) - - /** - * Build a help command by replacing `%c` with the bot's pub/priv command, and `%n` with the bot's - * nick. - */ - @JvmStatic - fun helpCmdSyntax(text: String, botNick: String, isPrivate: Boolean): String { - val replace = arrayOf(if (isPrivate) "/msg $botNick" else "$botNick:", botNick) - return text.replaceEach(searchFlags, replace) - } - - /** - * Returns a formatted help string. - */ - @JvmStatic - @JvmOverloads - fun helpFormat(help: String, isBold: Boolean = true, isIndent: Boolean = true): String { - val s = if (isBold) help.bold() else help - return if (isIndent) s.prependIndent() else s - } - - /** - * Returns `true` if the specified user is an operator on the [channel]. - */ - @JvmStatic - fun GenericMessageEvent.isChannelOp(channel: String): Boolean { - return this.bot().userChannelDao.getChannel(channel).isOp(this.user) - } - - /** - * Returns `true` if a HTTP status code indicates a successful response. - */ - @JvmStatic - fun Int.isHttpSuccess() = this in 200..399 - - /** - * Returns the last item of a list of strings or empty if none. - */ - @JvmStatic - fun List.lastOrEmpty(): String { - return if (this.size >= 2) { - this.last() - } else - "" - } - - /** - * Load serial data from file. - */ - @JvmStatic - fun loadSerialData(file: String, default: Any, logger: Logger, description: String): Any { - val serialFile = Paths.get(file) - if (serialFile.exists() && serialFile.fileSize() > 0) { - try { - ObjectInputStream( - BufferedInputStream(Files.newInputStream(serialFile)) - ).use { input -> - if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") - return input.readObject() - } - } catch (e: IOException) { - logger.error("An IO error occurred loading the ${description}.", e) - } catch (e: ClassNotFoundException) { - logger.error("An error occurred loading the ${description}.", e) - } - } - return default - } - - /** - * Returns `true` if the list does not contain the given string. - */ - @JvmStatic - fun List.notContains(text: String, ignoreCase: Boolean = false) = this.none { it.equals(text, ignoreCase) } - - /** - * Obfuscates the given string. - */ - @JvmStatic - fun String.obfuscate(): String { - return if (isNotBlank()) { - "x".repeat(length) - } else this - } - - /** - * Returns the plural form of a word, if count > 1. - */ - @JvmStatic - fun String.plural(count: Long): String { - return if (count > 1) "${this}s" else this - } - - /** - * Makes the given string red. - */ - @JvmStatic - fun String?.red(): String = colorize(Colors.RED) - - /** - * Replaces all occurrences of Strings within another String. - */ - @JvmStatic - fun String.replaceEach(search: Array, replace: Array): String { - var result = this - if (search.size == replace.size) { - search.forEachIndexed { i, s -> - result = result.replace(s, replace[i]) - } - } - return result - } - - /** - * Makes the given string reverse color. - */ - @JvmStatic - fun String?.reverseColor(): String = colorize(Colors.REVERSE) - - /** - * Save data - */ - @JvmStatic - fun saveSerialData(file: String, data: Any, logger: Logger, description: String) { - try { - BufferedOutputStream(Files.newOutputStream(Paths.get(file))).use { bos -> - ObjectOutputStream(bos).use { output -> - if (logger.isDebugEnabled) logger.debug("Saving the ${description}.") - output.writeObject(data) - } - } - } catch (e: IOException) { - logger.error("Unable to save the ${description}.", e) - } - } - - /** - * Send a formatted commands/modules, etc. list. - */ - @JvmStatic - @JvmOverloads - fun GenericMessageEvent.sendList( - list: List, - maxPerLine: Int, - separator: String = " ", - isBold: Boolean = false, - isIndent: Boolean = false - ) { - var i = 0 - while (i < list.size) { - sendMessage( - helpFormat( - list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), - isBold, - isIndent - ), - ) - i += maxPerLine - } - } - - /** - * Sends a [message]. - */ - @JvmStatic - fun GenericMessageEvent.sendMessage(channel: String, message: Message) { - if (message.isNotice) { - bot().sendIRC().notice(user.nick, message.msg.colorize(message.color)) - } else if (message.isPrivate || this is PrivateMessageEvent || channel.isBlank()) { - respondPrivateMessage(message.msg.colorize(message.color)) - } else { - bot().sendIRC().message(channel, message.msg.colorize(message.color)) - } - } - - /** - * Sends a response as a private message or notice. - */ - @JvmStatic - fun GenericMessageEvent.sendMessage(message: String) { - if (this is PrivateMessageEvent) { - respondPrivateMessage(message) - } else { - bot().sendIRC().notice(user.nick, message) - } - } - - /** - * Returns today's date. - */ - @JvmStatic - fun today(): String = LocalDateTime.now().toIsoLocalDate() - - /** - * Converts a string to an int. - */ - @JvmStatic - fun String.toIntOrDefault(defaultValue: Int): Int { - return try { - toInt() - } catch (e: NumberFormatException) { - defaultValue - } - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun Date.toIsoLocalDate(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toIsoLocalDate() - } - - /** - * Returns the specified date as an ISO local date string. - */ - @JvmStatic - fun LocalDateTime.toIsoLocalDate(): String = format(DateTimeFormatter.ISO_LOCAL_DATE) - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun Date.toUtcDateTime(): String { - return LocalDateTime.ofInstant(toInstant(), ZoneId.systemDefault()).toUtcDateTime() - } - - /** - * Returns the specified date formatted as `yyyy-MM-dd HH:mm`. - */ - @JvmStatic - fun LocalDateTime.toUtcDateTime(): String = format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) - - /** - * Makes the given string bold. - */ - @JvmStatic - fun String?.underline(): String = colorize(Colors.UNDERLINE) - - - /** - * Converts XML/XHTML entities to plain text. - */ - @JvmStatic - fun String.unescapeXml(): String = Jsoup.parse(this).text() - - /** - * Reads contents of a URL. - */ - @JvmStatic - @Throws(IOException::class) - fun URL.reader(): UrlReaderResponse { - val connection = this.openConnection() as HttpURLConnection - try { - connection.setRequestProperty( - "User-Agent", - Constants.USER_AGENT - ) - return if (connection.responseCode.isHttpSuccess()) { - UrlReaderResponse( - connection.responseCode, - connection.inputStream.bufferedReader().use { it.readText() }) - } else { - UrlReaderResponse( - connection.responseCode, - connection.errorStream.bufferedReader().use { it.readText() }) - } - } finally { - connection.disconnect() - } - } - - /** - * Holds the [URL.reader] response code and body text. - */ - data class UrlReaderResponse(val responseCode: Int, val body: String) -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt deleted file mode 100644 index 4642f42..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/AbstractCommand.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * AbstractCommand.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -abstract class AbstractCommand { - abstract val name: String - abstract val help: List - abstract val isOpOnly: Boolean - abstract val isPublic: Boolean - abstract val isVisible: Boolean - - val properties: MutableMap = mutableMapOf() - - abstract fun commandResponse(channel: String, args: String, event: GenericMessageEvent) - - open fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (!isOpOnly || isOpOnly == event.isChannelOp(channel)) { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, event is PrivateMessageEvent || !isPublic)) - } - return true - } - return false - } - - open fun initProperties(vararg keys: String) { - keys.forEach { - properties[it] = "" - } - } - - open fun isEnabled(): Boolean { - return true - } - - open fun matches(message: String): Boolean { - return false - } - - open fun setProperty(key: String, value: String) { - properties[key] = value - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt deleted file mode 100644 index 0075293..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/ChannelFeed.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ChannelFeed.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.FeedReader -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -class ChannelFeed(channel: String) : AbstractCommand() { - override val name = channel - override val help = listOf("To list the last 5 posts from the channel's weblog feed:", helpFormat("%c $channel")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val FEED_PROP = "feed" - } - - init { - initProperties(FEED_PROP) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - properties[FEED_PROP]?.let { FeedReader(it, event).run() } - } - } - - override fun isEnabled(): Boolean { - return !properties[FEED_PROP].isNullOrBlank() - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt deleted file mode 100644 index cefcde3..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Cycle.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Cycle.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Cycle : AbstractCommand() { - private val wait = 10 - override val name = "cycle" - override val help = listOf("To have the bot leave the channel and come back:", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - if (event.isChannelOp(channel)) { - runBlocking { - launch { - sendIRC().message(channel, "${event.user.nick} asked me to leave. I'll be back!") - userChannelDao.getChannel(channel).send().part() - delay(wait * 1000L) - sendIRC().joinChannel(channel) - } - } - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt deleted file mode 100644 index d7577af..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Die.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Die.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Die : AbstractCommand() { - override val name = "die" - override val help = emptyList() - override val isOpOnly = true - override val isPublic = false - override val isVisible = false - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - if (event.isChannelOp(channel) && (properties[DIE_PROP].isNullOrBlank() || args == properties[DIE_PROP])) { - sendIRC().message(channel, "${event.user?.nick} has just signed my death sentence.") - stopBotReconnect() - sendIRC().quitServer("The Bot is Out There!") - } - } - } - - companion object { - const val DIE_PROP = "die" - } - - init { - initProperties(DIE_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt deleted file mode 100644 index 13b20b0..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Ignore.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Ignore.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.links.LinksManager -import org.pircbotx.hooks.types.GenericMessageEvent - -class Ignore : AbstractCommand() { - private val me = "me" - - init { - initProperties(IGNORE_PROP) - } - - override val name = IGNORE_CMD - override val help = listOf( - "To ignore a link posted to the channel:", - helpFormat("https://www.foo.bar %n"), - "To check your ignore status:", - helpFormat("%c $name"), - "To toggle your ignore status:", - helpFormat("%c $name $me") - ) - private val helpOp = help.plus( - arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name [ ...]")) - ) - - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val IGNORE_CMD = "ignore" - const val IGNORE_PROP = IGNORE_CMD - private val ignored = mutableSetOf() - - @JvmStatic - fun isNotIgnored(nick: String): Boolean { - return !ignored.contains(nick.lowercase()) - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val isMe = args.trim().equals(me, true) - if (isMe || !event.isChannelOp(channel)) { - val nick = event.user.nick.lowercase() - ignoreNick(nick, isMe, event) - } else { - ignoreOp(args, event) - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - private fun ignoreNick(sender: String, isMe: Boolean, event: GenericMessageEvent) { - if (isMe) { - if (ignored.remove(sender)) { - event.sendMessage("You are no longer ignored.") - } else { - ignored.add(sender) - event.sendMessage("You are now ignored.") - } - } else { - if (ignored.contains(sender)) { - event.sendMessage("You are currently ignored.") - } else { - event.sendMessage("You are not currently ignored.") - } - } - } - - private fun ignoreOp(args: String, event: GenericMessageEvent) { - if (args.isNotEmpty()) { - val nicks = args.lowercase().split(" ") - for (nick in nicks) { - val ignore = if (me == nick) { - nick.lowercase() - } else { - nick - } - if (!ignored.remove(ignore)) { - ignored.add(ignore) - } - } - } - - if (ignored.isNotEmpty()) { - event.sendMessage("The following nicks are ignored:") - event.sendList(ignored.sorted(), 8, isIndent = true) - } else { - event.sendMessage("No one is currently ${"ignored".bold()}.") - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (IGNORE_PROP == key) { - ignored.addAll(value.split(LinksManager.TAG_MATCH)) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt deleted file mode 100644 index 8e244cc..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Info.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Info.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.commands.seen.Seen -import net.thauvin.erik.mobibot.commands.tell.Tell -import org.pircbotx.hooks.types.GenericMessageEvent -import java.lang.management.ManagementFactory -import kotlin.time.DurationUnit -import kotlin.time.toDuration - -class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { - private val allVersions = listOf( - "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", - "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" - ) - override val name = "info" - override val help = listOf("To view information about the bot:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - /** - * Converts milliseconds to year month week day hour and minutes. - */ - @JvmStatic - fun Long.toUptime(): String { - this.toDuration(DurationUnit.MILLISECONDS).toComponents { wholeDays, hours, minutes, seconds, _ -> - val years = wholeDays / 365 - var days = wholeDays % 365 - val months = days / 30 - days %= 30 - val weeks = days / 7 - days %= 7 - - with(StringBuffer()) { - if (years > 0) { - append(years).append(" year".plural(years)).append(' ') - } - if (months > 0) { - append(months).append(" month".plural(months)).append(' ') - } - if (weeks > 0) { - append(weeks).append(" week".plural(weeks)).append(' ') - } - if (days > 0) { - append(days).append(" day".plural(days)).append(' ') - } - if (hours > 0) { - append(hours).append(" hour".plural(hours.toLong())).append(' ') - } - - if (minutes > 0) { - append(minutes).append(" minute".plural(minutes.toLong())) - } else { - append(seconds).append(" second".plural(seconds.toLong())) - } - - return toString() - } - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - event.sendList(allVersions, 1) - val info = StringBuilder() - info.append("Uptime: ") - .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) - .append(" [Entries: ") - .append(LinksManager.entries.links.size) - if (seen.isEnabled()) { - info.append(", Seen: ").append(seen.count()) - } - if (event.isChannelOp(channel)) { - if (tell.isEnabled()) { - info.append(", Messages: ").append(tell.size()) - } - if (LinksManager.socialManager.entriesCount() > 0) { - info.append(", Social: ").append(LinksManager.socialManager.entriesCount()) - } - } - info.append(", Recap: ").append(Recap.recaps.size).append(']') - event.sendMessage(info.toString()) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt deleted file mode 100644 index afa9046..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Me.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Me.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Me : AbstractCommand() { - override val name = "me" - override val help = listOf("To have the bot perform an action:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().action(channel, args) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt deleted file mode 100644 index 8668bf7..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Modules.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Modules.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import org.pircbotx.hooks.types.GenericMessageEvent - -class Modules(private val modules: List, private val disabledModules: List) : AbstractCommand() { - override val name = "modules" - override val help = listOf("To view a list of enabled/disabled modules:", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (modules.isEmpty()) { - event.respondPrivateMessage("There are no enabled modules.") - } else { - event.respondPrivateMessage("The enabled modules are: ") - event.sendList(modules, 7, isIndent = true) - } - if (disabledModules.isNotEmpty()) { - event.respondPrivateMessage("The disabled modules are: ") - event.sendList(disabledModules, 7, isIndent = true) - } - } else { - helpResponse(channel, args, event) - } - } -} - diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt deleted file mode 100644 index 14d8d8e..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Msg.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Msg.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Msg : AbstractCommand() { - override val name = "msg" - override val help = listOf( - "To have the bot send a private message to someone:", - helpFormat("%c $name ") - ) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - val msg = args.split(" ", limit = 2) - if (args.length > 2) { - event.bot().sendIRC().message(msg[0], msg[1]) - event.respondPrivateMessage("A message was sent to ${msg[0]}") - } else { - helpResponse(channel, args, event) - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt deleted file mode 100644 index 21c96b5..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Nick.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Nick.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Nick : AbstractCommand() { - override val name = "nick" - override val help = listOf("To change the bot's nickname:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().changeNick(args) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt deleted file mode 100644 index 500fd85..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Recap.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Recap.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import org.pircbotx.hooks.types.GenericMessageEvent -import java.time.Clock -import java.time.LocalDateTime - -class Recap : AbstractCommand() { - override val name = "recap" - override val help = listOf( - "To list the last 10 public channel messages:", - helpFormat("%c $name") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_RECAPS = 10 - - @JvmField - val recaps = mutableListOf() - - /** - * Stores the last 10 public messages and actions. - */ - @JvmStatic - fun storeRecap(sender: String, message: String, isAction: Boolean) { - recaps.add( - LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() - + " - $sender" + (if (isAction) " " else ": ") + message - ) - if (recaps.size > MAX_RECAPS) { - recaps.removeFirst() - } - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (recaps.isNotEmpty()) { - for (r in recaps) { - event.sendMessage(r) - } - } else { - event.sendMessage("Sorry, nothing to recap.") - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt deleted file mode 100644 index b9d410d..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Say.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Say.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import org.pircbotx.hooks.types.GenericMessageEvent - -class Say : AbstractCommand() { - override val name = "say" - override val help = listOf("To have the bot say something on the channel:", helpFormat("%c $name ")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.bot().sendIRC().message(channel, args) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt deleted file mode 100644 index 960b8aa..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Users.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Users.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import org.pircbotx.hooks.types.GenericMessageEvent - -class Users : AbstractCommand() { - override val name = "users" - override val help = listOf("To list the users present on the channel:", helpFormat("%c $name")) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val ch = event.bot().userChannelDao.getChannel(channel) - event.sendList(ch.users.map { if (it.channelsOpIn.contains(ch)) "@${it.nick}" else it.nick }, 8) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt deleted file mode 100644 index 62cb044..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/Versions.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Versions.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import org.pircbotx.PircBotX -import org.pircbotx.hooks.types.GenericMessageEvent - -class Versions : AbstractCommand() { - private val allVersions = listOf( - "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILD_DATE.toIsoLocalDate()})", - "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + - ", JVM ${System.getProperty("java.version")}", - "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" - ) - override val name = "versions" - override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) - override val isOpOnly = true - override val isPublic = false - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - event.sendList(allVersions, 1) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt deleted file mode 100644 index f0d9d0c..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Comment.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Comment.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Comment : AbstractCommand() { - override val name = COMMAND - override val help = listOf( - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, use its label: ", - helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), - "To delete a comment, use its label and a minus sign: ", - helpFormat("${Constants.LINK_CMD}1.1:-") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "comment" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split("[.:]".toRegex(), 3) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val entry: EntryLink = LinksManager.entries.links[entryIndex] - val commentIndex = cmds[1].toInt() - 1 - if (commentIndex < entry.comments.size) { - when (val cmd = cmds[2].trim()) { - "" -> showComment(entry, entryIndex, commentIndex, event) // L1.1: - "-" -> deleteComment(channel, entry, entryIndex, commentIndex, event) // L1.1:- - else -> { - if (cmd.startsWith('?')) { // L1.1:? - changeAuthor(channel, cmd, entry, entryIndex, commentIndex, event) - } else { // L1.1: - setComment(cmd, entry, entryIndex, commentIndex, event) - } - } - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - if (super.helpResponse(channel, topic, event)) { - if (event.isChannelOp(channel)) { - event.sendMessage("To change a comment's author:") - event.sendMessage(helpFormat("${Constants.LINK_CMD}1.1:?")) - } - return true - } - return false - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+\\.\\d+:.*".toRegex()) - } - - private fun changeAuthor( - channel: String, - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) && cmd.length > 1) { - val comment = entry.getComment(commentIndex) - comment.nick = cmd.substring(1) - event.sendMessage(printComment(entryIndex, commentIndex, comment)) - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to change the author of this comment for you.") - } - } - - private fun deleteComment( - channel: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { - entry.deleteComment(commentIndex) - event.sendMessage("Comment ${entryIndex.toLinkLabel()}.${commentIndex + 1} removed.") - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to delete this comment for you.") - } - } - - private fun setComment( - cmd: String, - entry: EntryLink, - entryIndex: Int, - commentIndex: Int, - event: GenericMessageEvent - ) { - entry.setComment(commentIndex, cmd, event.user.nick) - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) - LinksManager.entries.save() - } - - private fun showComment(entry: EntryLink, entryIndex: Int, commentIndex: Int, event: GenericMessageEvent) { - event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt deleted file mode 100644 index e688092..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManager.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * LinksManager.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Pinboard -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.today -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.Ignore.Companion.isNotIgnored -import net.thauvin.erik.mobibot.entries.Entries -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialManager -import org.jsoup.Jsoup -import org.pircbotx.hooks.types.GenericMessageEvent -import java.io.IOException - -class LinksManager : AbstractCommand() { - private val defaultTags: MutableList = mutableListOf() - private val keywords: MutableList = mutableListOf() - - override val name = Constants.LINK_CMD - override val help = emptyList() - override val isOpOnly = false - override val isPublic = false - override val isVisible = false - - init { - initProperties(TAGS_PROP, KEYWORDS_PROP) - } - - companion object { - val LINK_MATCH = "^[hH][tT][tT][pP](|[sS])://.*".toRegex() - const val KEYWORDS_PROP = "tags-keywords" - const val TAGS_PROP = "tags" - val TAG_MATCH = ", *| +".toRegex() - - /** - * Entries array - */ - @JvmField - val entries = Entries() - - /** - * Pinboard handler. - */ - @JvmField - val pinboard = Pinboard() - - /** - * Social Manager handler. - */ - @JvmField - val socialManager = SocialManager() - - /** - * Let the user know if the entries are too old to be modified. - */ - @JvmStatic - fun isUpToDate(event: GenericMessageEvent): Boolean { - if (entries.lastPubDate != today()) { - event.sendMessage("The links are too old to be updated.") - return false - } - return true - } - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.split(" ".toRegex(), 2) - val sender = event.user.nick - val botNick = event.bot().nick - val login = event.user.login - - if (isNotIgnored(sender) && (cmds.size == 1 || !cmds[1].contains(botNick))) { - val link = cmds[0].trim() - if (!isDupEntry(link, event)) { - var title = "" - val tags = ArrayList(defaultTags) - if (cmds.size == 2) { - val data = cmds[1].trim().split("${Tags.COMMAND}:", limit = 2) - title = data[0].trim() - if (data.size > 1) { - tags.addAll(data[1].split(TAG_MATCH)) - } - } - - if (title.isBlank()) { - title = fetchTitle(link) - } - - if (title != Constants.NO_TITLE) { - matchTagKeywords(title, tags) - } - - // Links are old, clear them - if (entries.lastPubDate != today()) { - entries.links.clear() - } - - val entry = EntryLink(link, title, sender, login, channel, tags) - entries.links.add(entry) - val index = entries.links.lastIndexOf(entry) - event.sendMessage(printLink(index, entry)) - - pinboard.addPin(event.bot().serverHostname, entry) - - // Queue link for posting to social media. - socialManager.queueEntry(index) - - entries.save() - - if (Constants.NO_TITLE == entry.title) { - event.sendMessage("Please specify a title, by typing:") - event.sendMessage(helpFormat("${index.toLinkLabel()}:|This is the title")) - } - } - } - } - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean = false - - override fun matches(message: String): Boolean { - return message.matches(LINK_MATCH) - } - - internal fun fetchTitle(link: String): String { - try { - val html = Jsoup.connect(link) - .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") - .get() - val title = html.title() - if (title.isNotBlank()) { - return title - } - } catch (ignore: IOException) { - // Do nothing - } - return Constants.NO_TITLE - } - - private fun isDupEntry(link: String, event: GenericMessageEvent): Boolean { - synchronized(entries) { - return try { - val match = entries.links.single { it.link == link } - event.sendMessage( - "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) - ) - true - } catch (ignore: NoSuchElementException) { - false - } - } - } - - internal fun matchTagKeywords(title: String, tags: MutableList) { - for (match in keywords) { - val m = Regex.escape(match) - if (title.matches("(?i).*\\b$m\\b.*".toRegex())) { - tags.add(match) - } - } - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (KEYWORDS_PROP == key) { - keywords.addAll(value.split(TAG_MATCH)) - } else if (TAGS_PROP == key) { - defaultTags.addAll(value.split(TAG_MATCH)) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt deleted file mode 100644 index a47021b..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Posting.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Posting.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Posting : AbstractCommand() { - override val name = "posting" - override val help = listOf( - "Post a URL, by saying it on a line on its own:", - helpFormat(" [] ${Tags.COMMAND}: <+tag> [...]]"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", - "To add a title, use its label and a pipe:", - helpFormat("${Constants.LINK_CMD}1:|This is the title"), - "To add a comment:", - helpFormat("${Constants.LINK_CMD}1:This is a comment"), - "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", - "To edit a comment, see: ", - helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split(":", limit = 2) - val entryIndex = cmds[0].toInt() - 1 - - if (entryIndex < entries.links.size) { - val cmd = cmds[1].trim() - if (cmd.isBlank()) { - showEntry(entryIndex, event) // L1: - } else if (LinksManager.isUpToDate(event)) { - if (cmd == "-") { - removeEntry(channel, entryIndex, event) // L1:- - } else { - when (cmd[0]) { - '|' -> changeTitle(cmd, entryIndex, event) // L1:|<title> - '=' -> changeUrl(channel, cmd, entryIndex, event) // L1:=<url> - '?' -> changeAuthor(channel, cmd, entryIndex, event) // L1:?<author> - else -> addComment(cmd, entryIndex, event) // L1:<comment> - } - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("${Constants.LINK_CMD}\\d+:.*".toRegex()) - } - - private fun addComment(cmd: String, entryIndex: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[entryIndex] - val commentIndex = entry.addComment(cmd, event.user.nick) - val comment = entry.getComment(commentIndex) - event.sendMessage(EntriesUtils.printComment(entryIndex, commentIndex, comment)) - entries.save() - } - - private fun changeTitle(cmd: String, entryIndex: Int, event: GenericMessageEvent) { - if (cmd.length > 1) { - val entry: EntryLink = entries.links[entryIndex] - entry.title = cmd.substring(1).trim() - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) - entries.save() - } - } - - private fun changeUrl(channel: String, cmd: String, entryIndex: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[entryIndex] - if (entry.login == event.user.login || event.isChannelOp(channel)) { - val link = cmd.substring(1) - if (link.matches(LinksManager.LINK_MATCH)) { - val oldLink = entry.link - entry.link = link - LinksManager.pinboard.updatePin(event.bot().serverHostname, oldLink, entry) - event.sendMessage(EntriesUtils.printLink(entryIndex, entry)) - entries.save() - } - } - } - - private fun changeAuthor(channel: String, cmd: String, index: Int, event: GenericMessageEvent) { - if (event.isChannelOp(channel)) { - if (cmd.length > 1) { - val entry: EntryLink = entries.links[index] - entry.nick = cmd.substring(1) - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printLink(index, entry)) - entries.save() - } - } else { - event.sendMessage("Please ask a channel op to change the author of this link for you.") - } - } - - private fun removeEntry(channel: String, index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - if (entry.login == event.user.login || event.isChannelOp(channel)) { - LinksManager.pinboard.deletePin(entry) - LinksManager.socialManager.removeEntry(index) - entries.links.removeAt(index) - event.sendMessage("Entry ${index.toLinkLabel()} removed.") - entries.save() - } else { - event.sendMessage("Please ask a channel op to remove this entry for you.") - } - } - - private fun showEntry(index: Int, event: GenericMessageEvent) { - val entry: EntryLink = entries.links[index] - event.sendMessage(EntriesUtils.printLink(index, entry)) - if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) - } - if (entry.comments.isNotEmpty()) { - val comments = entry.comments - for (i in comments.indices) { - event.sendMessage(EntriesUtils.printComment(index, i, comments[i])) - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt deleted file mode 100644 index 0d73f6e..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/Tags.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Tags.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.types.GenericMessageEvent - -class Tags : AbstractCommand() { - override val name = COMMAND - override val help = listOf( - "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", - helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val COMMAND = "tags" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - val cmds = args.substring(1).split("${Constants.TAG_CMD}:", limit = 2) - val index = cmds[0].toInt() - 1 - - if (index < LinksManager.entries.links.size && LinksManager.isUpToDate(event)) { - val cmd = cmds[1].trim() - val entry: EntryLink = LinksManager.entries.links[index] - if (cmd.isNotEmpty()) { - if (entry.login == event.user.login || event.isChannelOp(channel)) { - entry.setTags(cmd) - LinksManager.pinboard.updatePin(event.bot().serverHostname, entry.link, entry) - event.sendMessage(EntriesUtils.printTags(index, entry)) - LinksManager.entries.save() - } else { - event.sendMessage("Please ask a channel op to change the tags for you.") - } - } else { - if (entry.tags.isNotEmpty()) { - event.sendMessage(EntriesUtils.printTags(index, entry)) - } else { - event.sendMessage("The entry has no tags. Why don't add some?") - } - } - } - } - - override fun matches(message: String): Boolean { - return message.matches("^${Constants.LINK_CMD}\\d+${Constants.TAG_CMD}:.*".toRegex()) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt deleted file mode 100644 index 6891c2d..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/links/View.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * View.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.LinksManager.Companion.entries -import net.thauvin.erik.mobibot.entries.EntriesUtils -import net.thauvin.erik.mobibot.entries.EntryLink -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -class View : AbstractCommand() { - override val name = VIEW_CMD - override val help = listOf( - "To list or search the current URL posts:", - helpFormat("%c $name [<start>] [<query>]") - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - companion object { - const val MAX_ENTRIES = 6 - const val VIEW_CMD = "view" - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (entries.links.isNotEmpty()) { - val p = parseArgs(args) - showPosts(p.first, p.second, event) - } else { - event.sendMessage("There is currently nothing to view. Why don't you post something?") - } - } - - internal fun parseArgs(args: String): Pair<Int, String> { - var query = args.lowercase().trim() - var start = 0 - if (query.isEmpty() && entries.links.size > MAX_ENTRIES) { - start = entries.links.size - MAX_ENTRIES - } - if (query.matches("^\\d+(| .*)".toRegex())) { // view [<start>] [<query>] - val split = query.split(" ", limit = 2) - try { - start = split[0].toInt() - 1 - query = split.lastOrEmpty().trim() - if (start > entries.links.size) { - start = 0 - } - } catch (ignore: NumberFormatException) { - // Do nothing - } - } - return Pair(start, query) - } - - private fun showPosts(start: Int, query: String, event: GenericMessageEvent) { - var index = start - var entry: EntryLink - var sent = 0 - while (index < entries.links.size && sent < MAX_ENTRIES) { - entry = entries.links[index] - if (query.isNotBlank()) { - if (entry.matches(query)) { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - } else { - event.sendMessage(EntriesUtils.printLink(index, entry, true)) - sent++ - } - index++ - if (sent == MAX_ENTRIES && index < entries.links.size) { - event.sendMessage("To view more, try: ") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) - ) - ) - } - } - if (sent == 0) { - event.sendMessage("No matches. Please try again.") - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt deleted file mode 100644 index f44b357..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/NickComparator.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * NickComparator.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.seen - -import java.io.Serializable - -class NickComparator : Comparator<String>, Serializable { - override fun compare(a: String, b: String): Int { - return a.lowercase().compareTo(b.lowercase()) - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt deleted file mode 100644 index 8af98dc..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/Seen.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Seen.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.seen - -import com.google.common.collect.ImmutableSortedSet -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import org.pircbotx.User -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - - -class Seen(private val serialObject: String) : AbstractCommand() { - private val logger: Logger = LoggerFactory.getLogger(Seen::class.java) - private val allKeyword = "all" - val seenNicks = TreeMap<String, SeenNick>(NickComparator()) - - override val name = "seen" - override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) - private val helpOp = help.plus( - arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) - ) - override val isOpOnly = false - override val isPublic = true - override val isVisible = true - - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - if (args.isNotBlank() && !args.contains(' ')) { - val ch = event.bot().userChannelDao.getChannel(channel) - if (args == allKeyword && ch.isOp(event.user) && seenNicks.isNotEmpty()) { - event.sendMessage("The ${"seen".bold()} nicks are:") - event.sendList(seenNicks.keys.toList(), 7, separator = ", ", isIndent = true) - return - } - ch.users.forEach { - if (args.equals(it.nick, true)) { - event.sendMessage("${it.nick} is on ${channel}.") - return - } - } - if (seenNicks.containsKey(args)) { - val seenNick = seenNicks.getValue(args) - val lastSeen = System.currentTimeMillis() - seenNick.lastSeen - event.sendMessage("${seenNick.nick} was last seen on $channel ${lastSeen.toUptime()} ago.") - return - } - event.sendMessage("I haven't seen $args on $channel lately.") - } else { - helpResponse(channel, args, event) - } - } - } - - fun add(nick: String) { - if (isEnabled()) { - seenNicks[nick] = SeenNick(nick, System.currentTimeMillis()) - save() - } - } - - fun add(users: ImmutableSortedSet<User>) { - if (isEnabled()) { - users.forEach { - seenNicks[it.nick] = SeenNick(it.nick, System.currentTimeMillis()) - } - save() - } - } - - fun clear() { - seenNicks.clear() - } - - fun count(): Int = seenNicks.size - - override fun helpResponse(channel: String, topic: String, event: GenericMessageEvent): Boolean { - return if (event.isChannelOp(channel)) { - for (h in helpOp) { - event.sendMessage(Utils.helpCmdSyntax(h, event.bot().nick, true)) - } - true - } else { - super.helpResponse(channel, topic, event) - } - } - - fun load() { - if (isEnabled()) { - @Suppress("UNCHECKED_CAST") - seenNicks.putAll( - loadSerialData( - serialObject, - TreeMap<String, SeenNick>(), - logger, - "seen nicknames" - ) as TreeMap<String, SeenNick> - ) - } - } - - fun save() { - saveSerialData(serialObject, seenNicks, logger, "seen nicknames") - } - - init { - load() - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt deleted file mode 100644 index 21d7cb9..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenNick.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SeenNick.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.seen - -import java.io.Serializable - -data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt deleted file mode 100644 index 26fe803..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/Tell.kt +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Tell.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.isChannelOp -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.reverseColor -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.toIntOrDefault -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import net.thauvin.erik.mobibot.commands.AbstractCommand -import net.thauvin.erik.mobibot.commands.links.View -import org.pircbotx.PircBotX -import org.pircbotx.hooks.events.MessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent -import org.pircbotx.hooks.types.GenericUserEvent - -/** - * The `Tell` command. - */ -class Tell(private val serialObject: String) : AbstractCommand() { - // Messages queue - private val messages: MutableList<TellMessage> = mutableListOf() - - // Maximum number of days to keep messages - private var maxDays = 7 - - // Message maximum queue size - private var maxSize = 50 - - /** - * The tell command. - */ - override val name = "tell" - - override val help = listOf( - "To send a message to someone when they join the channel:", - helpFormat("%c $name <nick> <message>"), - "To view queued and sent messages:", - helpFormat("%c $name ${View.VIEW_CMD}"), - "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' - ) - override val isOpOnly: Boolean = false - override val isPublic: Boolean = isEnabled() - override val isVisible: Boolean = isEnabled() - - /** - * Cleans the messages queue. - */ - private fun clean(): Boolean { - return TellManager.clean(messages, maxDays.toLong()) - } - - override fun commandResponse(channel: String, args: String, event: GenericMessageEvent) { - if (isEnabled()) { - when { - args.isBlank() -> { - helpResponse(channel, args, event) - } - - args.startsWith(View.VIEW_CMD) -> { - if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { - viewAll(event) - } else { - viewMessages(event) - } - } - - args.startsWith("$TELL_DEL_KEYWORD ") -> { - deleteMessage(channel, args, event) - } - - else -> { - newMessage(channel, args, event) - } - } - if (clean()) { - save() - } - } - } - - // Delete message. - private fun deleteMessage(channel: String, args: String, event: GenericMessageEvent) { - val split = args.split(" ") - if (split.size == 2) { - val id = split[1] - if (TELL_ALL_KEYWORD.equals(id, ignoreCase = true)) { - if (messages.removeIf { it.sender.equals(event.user.nick, true) && it.isReceived }) { - save() - event.sendMessage("Delivered messages have been deleted.") - } else { - event.sendMessage("No delivered messages were found.") - } - } else { - if (messages.removeIf { - it.id == id && - (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) - }) { - save() - event.sendMessage("The message was deleted from the queue.") - } else { - event.sendMessage("The specified message [ID $id] could not be found.") - } - } - } else { - helpResponse(channel, args, event) - } - } - - override fun isEnabled(): Boolean { - return maxSize > 0 && maxDays > 0 - } - - override fun setProperty(key: String, value: String) { - super.setProperty(key, value) - if (MAX_DAYS_PROP == key) { - maxDays = value.toIntOrDefault(maxDays) - } else if (MAX_SIZE_PROP == key) { - maxSize = value.toIntOrDefault(maxSize) - } - } - - // New message. - private fun newMessage(channel: String, args: String, event: GenericMessageEvent) { - val split = args.split(" ".toRegex(), 2) - if (split.size == 2 && split[1].isNotBlank() && split[1].contains(" ")) { - if (messages.size < maxSize) { - val message = TellMessage(event.user.nick, split[0], split[1].trim()) - messages.add(message) - save() - event.sendMessage("Message [ID ${message.id}] was queued for ${message.recipient.bold()}") - } else { - event.sendMessage("Sorry, the messages queue is currently full.") - } - } else { - helpResponse(channel, args, event) - } - } - - /** - * Saves the messages queue. - */ - private fun save() { - TellManager.save(serialObject, messages) - } - - /** - * Checks and sends messages. - */ - fun send(event: GenericUserEvent) { - val nickname = event.user.nick - if (isEnabled() && nickname != event.getBot<PircBotX>().nick) { - messages.filter { it.isMatch(nickname) }.forEach { message -> - if (message.recipient.equals(nickname, ignoreCase = true) && !message.isReceived) { - if (message.sender == nickname) { - if (event !is MessageEvent) { - event.user.send().message( - "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" - ) - message.isReceived = true - message.isNotified = true - save() - } - } else { - event.user.send().message( - "${message.sender} wanted me to tell you: ${message.message.reverseColor()}" - ) - message.isReceived = true - save() - } - } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived - && !message.isNotified - ) { - event.user.send().message( - "Your message ${"[ID ${message.id}]".reverseColor()} was sent to " - + "${message.recipient.bold()} on ${message.receptionDate}" - ) - message.isNotified = true - save() - } - } - } - } - - /** - * Returns the messages queue size. - * - * @return The size. - */ - fun size(): Int = messages.size - - // View all messages. - private fun viewAll(event: GenericMessageEvent) { - if (messages.isNotEmpty()) { - for (message in messages) { - event.sendMessage( - "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + - (if (message.isReceived) "DELIVERED]" else "QUEUED]") - ) - } - } else { - event.sendMessage("There are no messages in the queue.") - } - } - - // View messages. - private fun viewMessages(event: GenericMessageEvent) { - var hasMessage = false - for (message in messages.filter { it.isMatch(event.user.nick) }) { - if (!hasMessage) { - hasMessage = true - event.sendMessage("Here are your messages: ") - } - if (message.isReceived) { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" - ) - } else { - event.sendMessage( - message.sender.bold() + ARROW + message.recipient.bold() + - " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" - ) - } - event.sendMessage(helpFormat(message.message)) - } - if (!hasMessage) { - event.sendMessage("You have no messages in the queue.") - } else { - event.sendMessage("To delete one or all delivered messages:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) - ) - ) - event.sendMessage(help.last()) - } - } - - companion object { - /** - * Max days property. - */ - const val MAX_DAYS_PROP = "tell-max-days" - - /** - * Max size property. - */ - const val MAX_SIZE_PROP = "tell-max-size" - - // Arrow - private const val ARROW = " --> " - - // All keyword - private const val TELL_ALL_KEYWORD = "all" - - // The delete command. - private const val TELL_DEL_KEYWORD = "del" - } - - /** - * Creates a new instance. - */ - init { - initProperties(MAX_DAYS_PROP, MAX_SIZE_PROP) - - // Load the message queue - messages.addAll(TellManager.load(serialObject)) - if (clean()) { - save() - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt deleted file mode 100644 index f193a3c..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellManager.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * TellManager.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.tell - -import net.thauvin.erik.mobibot.Utils.loadSerialData -import net.thauvin.erik.mobibot.Utils.saveSerialData -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.time.Clock -import java.time.LocalDateTime - -/** - * The Tell Messages Manager. - */ -object TellManager { - private val logger: Logger = LoggerFactory.getLogger(TellManager::class.java) - - /** - * Cleans the messages queue. - */ - @JvmStatic - fun clean(tellMessages: MutableList<TellMessage>, tellMaxDays: Long): Boolean { - if (logger.isDebugEnabled) logger.debug("Cleaning the messages.") - val today = LocalDateTime.now(Clock.systemUTC()) - return tellMessages.removeIf { o: TellMessage -> o.queued.plusDays(tellMaxDays).isBefore(today) } - } - - /** - * Loads the messages. - */ - @JvmStatic - fun load(file: String): List<TellMessage> { - @Suppress("UNCHECKED_CAST") - return loadSerialData(file, emptyList<TellMessage>(), logger, "message queue") as List<TellMessage> - } - - /** - * Saves the messages. - */ - @JvmStatic - fun save(file: String, messages: List<TellMessage?>?) { - if (messages != null) { - saveSerialData(file, messages, logger, "messages") - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt deleted file mode 100644 index 1f55687..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessage.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * TellMessage.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.tell - -import java.io.Serializable -import java.time.Clock -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -/** - * Tell Message. - */ -class TellMessage( - /** - * Returns the message's sender. - */ - val sender: String, - - /** - * Returns the message's recipient. - */ - val recipient: String, - - /** - * Returns the message text. - */ - val message: String -) : Serializable { - /** - * Returns the queued date/time. - */ - var queued: LocalDateTime = LocalDateTime.now(Clock.systemUTC()) - - /** - * Returns the message id. - */ - var id: String = queued.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) - - /** - * Returns `true` if a notification was sent. - */ - var isNotified = false - - /** - * Returns `true` if the message was received. - */ - var isReceived = false - set(value) { - if (value) { - receptionDate = LocalDateTime.now(Clock.systemUTC()) - } - field = value - } - - /** - * Returns the message creating date. - */ - var receptionDate: LocalDateTime = LocalDateTime.MIN - - /** - * Matches the message sender or recipient. - */ - fun isMatch(nick: String?): Boolean { - return sender.equals(nick, ignoreCase = true) || recipient.equals(nick, ignoreCase = true) - } - - override fun toString(): String { - return ("TellMessage{id='$id', isNotified=$isNotified, isReceived=$isReceived, message='$message', " + - "queued=$queued, received=$receptionDate, recipient='$recipient', sender='$sender'}") - } - - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 2L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt deleted file mode 100644 index 4e187d4..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/Entries.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Entries.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import net.thauvin.erik.mobibot.Utils.today - -class Entries( - var channel: String = "", - var ircServer: String = "", - var logsDir: String = "", - var backlogs: String = "" -) { - val links = mutableListOf<EntryLink>() - - var lastPubDate = today() - - fun load() { - lastPubDate = FeedsManager.loadFeed(this) - } - - fun save() { - lastPubDate = today() - FeedsManager.saveFeed(this) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt deleted file mode 100644 index 1588704..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtils.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * EntriesUtils.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.green - -/** - * Entries utilities. - */ -object EntriesUtils { - /** - * Prints an entry's comment for display on the channel. - */ - @JvmStatic - fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = - ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") - - /** - * Prints an entry's link for display on the channel. - */ - @JvmStatic - @JvmOverloads - fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { - val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") - .append('[').append(entry.nick).append(']') - if (isView && entry.comments.isNotEmpty()) { - buff.append("[+").append(entry.comments.size).append(']') - } - buff.append(' ') - with(entry) { - if (Constants.NO_TITLE == title) { - buff.append(title) - } else { - buff.append(title.bold()) - } - buff.append(" ( ").append(link.green()).append(" )") - } - return buff.toString() - } - - /** - * Prints an entry's tags/categories for display on the channel. e.g. L1T: tag1, tag2 - */ - @JvmStatic - fun printTags(entryIndex: Int, entry: EntryLink): String = - entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") - - /** - * Builds link label based on its index. e.g: L1 - */ - @JvmStatic - fun Int.toLinkLabel(): String = Constants.LINK_CMD + (this + 1) -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt deleted file mode 100644 index 1826101..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryComment.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * EntryComment.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import java.io.Serializable -import java.time.LocalDateTime - -/** - * Entry comments data class. - */ -data class EntryComment(var comment: String, var nick: String) : Serializable { - /** - * Creation date. - */ - val date: LocalDateTime = LocalDateTime.now() - - override fun toString(): String = "EntryComment{comment='$comment', date=$date, nick='$nick'}" - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt deleted file mode 100644 index a807f07..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/EntryLink.kt +++ /dev/null @@ -1,213 +0,0 @@ -/* - * EntryLink.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import net.thauvin.erik.mobibot.commands.links.LinksManager -import java.io.Serializable -import java.util.* - -/** - * The class used to store link entries. - */ -class EntryLink( - // Link's comments - val comments: MutableList<EntryComment> = mutableListOf(), - - // Tags/categories - val tags: MutableList<SyndCategory> = mutableListOf(), - - // Channel - var channel: String, - - // Creation date - var date: Date = Calendar.getInstance().time, - - // Link's URL - var link: String, - - // Author's login - var login: String = "", - - // Author's nickname - var nick: String, - - // Link's title - var title: String -) : Serializable { - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - login: String, - channel: String, - tags: List<String?> - ) : this(link = link, title = title, nick = nick, login = login, channel = channel) { - setTags(tags) - } - - /** - * Creates a new entry. - */ - constructor( - link: String, - title: String, - nick: String, - channel: String, - date: Date, - tags: List<SyndCategory> - ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { - this.tags.addAll(tags) - } - - /** - * Adds a new comment - */ - fun addComment(comment: EntryComment): Int { - comments.add(comment) - return comments.lastIndex - } - - /** - * Adds a new comment. - */ - fun addComment(comment: String, nick: String): Int { - return addComment(EntryComment(comment, nick)) - } - - /** - * Deletes a specific comment. - */ - fun deleteComment(index: Int): Boolean { - if (index < comments.size) { - comments.removeAt(index) - return true - } - return false - } - - /** - * Deletes a comment. - */ - fun deleteComment(entryComment: EntryComment): Boolean { - return comments.remove(entryComment) - } - - /** - * Formats the tags. - */ - fun formatTags(sep: String, prefix: String = ""): String { - return tags.joinToString(separator = sep, prefix = prefix) { it.name } - } - - /** - * Returns a comment. - */ - fun getComment(index: Int): EntryComment = comments[index] - - /** - * Returns true if a string is contained in the link, title, or nick. - */ - fun matches(match: String?): Boolean { - return if (match.isNullOrEmpty()) { - false - } else { - link.contains(match, true) || title.contains(match, true) || nick.contains(match, true) - } - } - - /** - * Sets a comment. - */ - fun setComment(index: Int, comment: String?, nick: String?) { - if (index < comments.size && !comment.isNullOrBlank() && !nick.isNullOrBlank()) { - comments[index] = EntryComment(comment, nick) - } - } - - /** - * Sets the tags. - */ - fun setTags(tags: String) { - setTags(tags.split(LinksManager.TAG_MATCH)) - } - - /** - * Sets the tags. - */ - private fun setTags(tags: List<String?>) { - if (tags.isNotEmpty()) { - var category: SyndCategoryImpl - for (tag in tags) { - if (!tag.isNullOrBlank()) { - val t = tag.lowercase() - val mod = t[0] - if (mod == '-') { - // Don't remove the channel tag - if (channel.substring(1) != t.substring(1)) { - category = SyndCategoryImpl() - category.name = t.substring(1) - this.tags.remove(category) - } - } else { - category = SyndCategoryImpl() - if (mod == '+') { - category.name = t.substring(1) - } else { - category.name = t - } - if (!this.tags.contains(category)) { - this.tags.add(category) - } - } - } - } - } - } - - /** - * Returns a string representation of the object. - */ - override fun toString(): String { - return ("EntryLink{channel='$channel', comments=$comments, date=$date, link='$link', login='$login'," + - "nick='$nick', tags=$tags, title='$title'}") - } - - companion object { - // Serial version UID - @Suppress("ConstPropertyName") - private const val serialVersionUID: Long = 1L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt deleted file mode 100644 index a881204..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/entries/FeedsManager.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * FeedsManager.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import com.rometools.rome.feed.synd.* -import com.rometools.rome.io.FeedException -import com.rometools.rome.io.SyndFeedInput -import com.rometools.rome.io.SyndFeedOutput -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.Utils.today -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.io.InputStreamReader -import java.io.OutputStreamWriter -import java.nio.charset.StandardCharsets -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* -import kotlin.io.path.exists - -/** - * Manages the RSS feeds. - */ -class FeedsManager private constructor() { - companion object { - private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) - - // The file containing the current entries. - private const val CURRENT_XML = "current.xml" - - // The .xml extension. - private const val DOT_XML = ".xml" - - /** - * Loads the current feed. - */ - @JvmStatic - @Throws(IOException::class, FeedException::class) - fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String { - entries.links.clear() - val xml = Paths.get("${entries.logsDir}${currentFile}") - var pubDate = today() - if (xml.exists()) { - val input = SyndFeedInput() - InputStreamReader( - Files.newInputStream(xml), StandardCharsets.UTF_8 - ).use { reader -> - val feed = input.build(reader) - pubDate = feed.publishedDate.toIsoLocalDate() - val items = feed.entries - var entry: EntryLink - for (i in items.indices.reversed()) { - with(items[i]) { - entry = EntryLink( - link, - title, - author.substring(author.lastIndexOf('(') + 1, author.length - 1), - entries.channel, - publishedDate, - categories - ) - var split: List<String> - for (comment in description.value.split("<br/>")) { - split = comment.split(": ".toRegex(), 2) - if (split.size == 2) { - entry.addComment(comment = split[1].trim(), nick = split[0].trim()) - } - } - } - entries.links.add(entry) - } - } - } else { - // Create an empty feed. - saveFeed(entries) - } - return pubDate - } - - /** - * Saves the feeds. - */ - @JvmStatic - fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) { - if (logger.isDebugEnabled) logger.debug("Saving the feeds...") - if (entries.logsDir.isNotBlank()) { - try { - val output = SyndFeedOutput() - val rss: SyndFeed = SyndFeedImpl() - val items: MutableList<SyndEntry> = mutableListOf() - var item: SyndEntry - OutputStreamWriter( - Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 - ).use { fw -> - with(rss) { - feedType = "rss_2.0" - title = "${entries.channel} IRC Links" - description = "Links from ${entries.ircServer} on ${entries.channel}" - if (entries.backlogs.isNotBlank()) link = entries.backlogs - publishedDate = Calendar.getInstance().time - language = "en" - } - val buff: StringBuilder = StringBuilder() - for (i in entries.links.indices.reversed()) { - with(entries.links[i]) { - buff.setLength(0) - buff.append("Posted by <b>") - .append(nick) - .append("</b> on <a href=\"irc://") - .append(entries.ircServer).append('/') - .append(channel) - .append("\"><b>") - .append(channel) - .append("</b></a>") - if (comments.isNotEmpty()) { - buff.append(" <br/><br/>") - for (j in comments.indices) { - if (j > 0) { - buff.append(" <br/>") - } - buff.append(comments[j].nick).append(": ").append(comments[j].comment) - } - } - item = SyndEntryImpl() - item.link = link - item.description = SyndContentImpl().apply { value = buff.toString() } - item.title = title - item.publishedDate = date - item.author = "${channel.removePrefix("#")}@${entries.ircServer} ($nick)" - item.categories = tags - items.add(item) - } - } - rss.entries = items - if (logger.isDebugEnabled) logger.debug("Writing the entries feed.") - output.output(rss, fw) - } - OutputStreamWriter( - Files.newOutputStream( - Paths.get( - entries.logsDir + today() + DOT_XML - ) - ), StandardCharsets.UTF_8 - ).use { fw -> output.output(rss, fw) } - } catch (e: FeedException) { - if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) - } catch (e: IOException) { - if (logger.isWarnEnabled) - logger.warn("An IO error occurred while generating the entries feed.", e) - } - } else { - if (logger.isWarnEnabled) { - logger.warn("Unable to generate the entries feed. A required property is missing.") - } - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt deleted file mode 100644 index 1ced830..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/AbstractModule.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * AbstractModule.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.events.PrivateMessageEvent -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The `Module` abstract class. - */ -abstract class AbstractModule { - /** - * The module name. - */ - abstract val name: String - - /** - * The module's commands, if any. - */ - @JvmField - val commands: MutableList<String> = mutableListOf() - - @JvmField - val help: MutableList<String> = mutableListOf() - val properties: MutableMap<String, String> = mutableMapOf() - - /** - * Responds to a command. - */ - abstract fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) - - /** - * Returns the module's property keys. - */ - val propertyKeys: Set<String> - get() = properties.keys - - /** - * Returns `true` if the module has properties. - */ - fun hasProperties(): Boolean { - return properties.isNotEmpty() - } - - /** - * Responds with the module's help. - */ - open fun helpResponse(event: GenericMessageEvent): Boolean { - for (h in help) { - event.sendMessage(helpCmdSyntax(h, event.bot().nick, isPrivateMsgEnabled && event is PrivateMessageEvent)) - } - return true - } - - /** - * Initializes the properties. - */ - fun initProperties(vararg keys: String) { - for (key in keys) { - properties[key] = "" - } - } - - /** - * Returns `true` if the module is enabled. - */ - val isEnabled: Boolean - get() = if (hasProperties()) { - isValidProperties - } else { - true - } - - /** - * Returns `true` if the module responds to private messages. - */ - open val isPrivateMsgEnabled: Boolean = false - - /** - * Ensures that all properties have values. - */ - open val isValidProperties: Boolean - get() { - for (s in properties.keys) { - if (properties[s].isNullOrBlank()) { - return false - } - } - return true - } - - /** - * Sets a property key and value. - */ - fun setProperty(key: String, value: String) { - if (key.isNotBlank()) { - properties[key] = value - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt deleted file mode 100644 index 7fd320f..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Calc.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Calc.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.objecthunter.exp4j.ExpressionBuilder -import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.text.DecimalFormat - -/** - * The Calc module. - */ -class Calc : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Calc::class.java) - - override val name = "Calc" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - event.respond(calculate(args)) - } catch (e: IllegalArgumentException) { - if (logger.isWarnEnabled) logger.warn("Failed to calculate: $args", e) - event.respond("No idea. This is the kind of math I don't get.") - } catch (e: UnknownFunctionOrVariableException) { - if (logger.isWarnEnabled) logger.warn("Unable to calculate: $args", e) - event.respond("No idea. I must've some form of Dyscalculia.") - } - } else { - helpResponse(event) - } - } - - companion object { - // Calc command - private const val CALC_CMD = "calc" - - /** - * Performs a calculation. e.g.: 1 + 1 * 2 - */ - @JvmStatic - @Throws(IllegalArgumentException::class) - fun calculate(query: String): String { - val decimalFormat = DecimalFormat("#.##") - val calc = ExpressionBuilder(query).build() - return query.replace(" ", "") + " = " + decimalFormat.format(calc.evaluate()).bold() - } - } - - init { - commands.add(CALC_CMD) - help.add("To solve a mathematical calculation:") - help.add(helpFormat("%c $CALC_CMD <calculation>")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt deleted file mode 100644 index fbf0e94..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * ChatGpt2.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import dev.langchain4j.model.openai.OpenAiChatModel -import dev.langchain4j.model.openai.OpenAiChatModelName -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -class ChatGpt2 : AbstractModule() { - val logger: Logger = LoggerFactory.getLogger(ChatGpt2::class.java) - - override val name = CHATGPT_NAME - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val answer = chat( - args.trim(), properties[API_KEY_PROP], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() - ) - if (answer.isNotBlank()) { - event.sendMessage(answer) - } else { - event.respond("$name is stumped.") - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } catch (e: NumberFormatException) { - if (logger.isErrorEnabled) logger.error("Invalid $MAX_TOKENS_PROP property.", e) - event.respond("The $name module is misconfigured.") - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The service name. - */ - const val CHATGPT_NAME = "ChatGPT" - - /** - * The API Key property. - */ - const val API_KEY_PROP = "chatgpt-api-key" - - /** - * The max tokens property. - */ - const val MAX_TOKENS_PROP = "chatgpt-max-tokens" - - // ChatGPT command - private const val CHATGPT_CMD = "chatgpt" - - @JvmStatic - @Throws(ModuleException::class) - fun chat(query: String, apiKey: String?, maxTokens: Int): String { - if (!apiKey.isNullOrEmpty()) { - try { - val model = OpenAiChatModel.builder() - .apiKey(apiKey) - .modelName(OpenAiChatModelName.GPT_4) - .maxTokens(maxTokens) - .build() - - return model.generate(query) - } catch (e: Exception) { - throw ModuleException( - "$CHATGPT_CMD($query): IO", - "An IO error has occurred while conversing with $CHATGPT_NAME.", - e - ) - } - } else { - throw ModuleException("$CHATGPT_CMD($query)", "No $CHATGPT_NAME API key specified.") - } - } - } - - init { - commands.add(CHATGPT_CMD) - with(help) { - add("To get answers from $name:") - add(Utils.helpFormat("%c $CHATGPT_CMD <query>")) - add("For example:") - add(Utils.helpFormat("%c $CHATGPT_CMD explain quantum computing in simple terms")) - add(Utils.helpFormat("%c $CHATGPT_CMD how do I make an HTTP request in Javascript?")) - } - initProperties(API_KEY_PROP, MAX_TOKENS_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt deleted file mode 100644 index 3334a90..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CryptoPrices.kt +++ /dev/null @@ -1,159 +0,0 @@ -/* - * CryptoPrices.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.crypto.CryptoException -import net.thauvin.erik.crypto.CryptoPrice -import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Cryptocurrency Prices module. - */ -class CryptoPrices : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CryptoPrices::class.java) - - override val name = "CryptoPrices" - - /** - * Returns the cryptocurrency market price from - * [Coinbase](https://docs.cdp.coinbase.com/coinbase-app/docs/api-prices#get-spot-price). - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (CURRENCIES.isEmpty()) { - try { - loadCurrencies() - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - - val debugMessage = "crypto($cmd $args)" - if (args == CODES_KEYWORD) { - event.sendMessage("The supported currencies are:") - event.sendList(ArrayList(CURRENCIES.keys), 10, isIndent = true) - } else if (args.matches("\\w+( [a-zA-Z]{3}+)?".toRegex())) { - try { - val price = currentPrice(args.split(' ')) - val amount = try { - price.toCurrency() - } catch (ignore: IllegalArgumentException) { - price.amount - } - event.respond("${price.base} current price is $amount [${CURRENCIES[price.currency]}]") - } catch (e: CryptoException) { - if (logger.isWarnEnabled) logger.warn("$debugMessage => ${e.statusCode}", e) - e.message?.let { - event.respond(it) - } - } catch (e: IOException) { - if (logger.isErrorEnabled) logger.error(debugMessage, e) - event.respond("An IO error has occurred while retrieving the cryptocurrency market price.") - } - } else { - helpResponse(event) - } - - } - - companion object { - // Crypto command - private const val CRYPTO_CMD = "crypto" - - // Fiat Currencies - private val CURRENCIES: MutableMap<String, String> = mutableMapOf() - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - /** - * Get current market price. - */ - @JvmStatic - fun currentPrice(args: List<String>): CryptoPrice { - return if (args.size == 2) - spotPrice(args[0], args[1]) - else - spotPrice(args[0]) - } - - /** - * For testing purposes. - */ - fun getCurrencyName(code: String): String? { - return CURRENCIES[code] - } - - /** - * Loads the Fiat currencies. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadCurrencies() { - try { - val json = JSONObject(CryptoPrice.apiCall(listOf("currencies"))) - val data = json.getJSONArray("data") - for (i in 0 until data.length()) { - val d = data.getJSONObject(i) - CURRENCIES[d.getString("id")] = d.getString("name") - } - } catch (e: CryptoException) { - throw ModuleException( - "loadCurrencies(): CE", - "An error has occurred while retrieving the currencies table.", - e - ) - } - } - } - - init { - commands.add(CRYPTO_CMD) - with(help) { - add("To retrieve a cryptocurrency's market price:") - add(helpFormat("%c $CRYPTO_CMD <symbol> [<currency>]")) - add("For example:") - add(helpFormat("%c $CRYPTO_CMD BTC")) - add(helpFormat("%c $CRYPTO_CMD ETH EUR")) - add(helpFormat("%c $CRYPTO_CMD ETH2 GPB")) - add("To list the supported currencies:") - add(helpFormat("%c $CRYPTO_CMD $CODES_KEYWORD")) - } - loadCurrencies() - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt deleted file mode 100644 index 2ff4715..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverter.kt +++ /dev/null @@ -1,222 +0,0 @@ -/* - * CurrencyConverter.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL -import java.text.DecimalFormat -import java.util.* - - -/** - * The CurrencyConverter module. - */ -class CurrencyConverter : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(CurrencyConverter::class.java) - - override val name = "CurrencyConverter" - - // Reload currency codes - private fun reload(apiKey: String?) { - if (!apiKey.isNullOrEmpty() && SYMBOLS.isEmpty()) { - try { - loadSymbols(apiKey) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - } - } - } - - /** - * Converts the specified currencies. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - reload(properties[API_KEY_PROP]) - - when { - SYMBOLS.isEmpty() -> { - event.respond(EMPTY_SYMBOLS_TABLE) - } - - args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { - val msg = convertCurrency(properties[API_KEY_PROP], args) - event.respond(msg.msg) - if (msg.isError) { - helpResponse(event) - } - } - - args.contains(CODES_KEYWORD) -> { - event.sendMessage("The supported currency codes are:") - event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) - } - - else -> { - helpResponse(event) - } - } - } - - override fun helpResponse(event: GenericMessageEvent): Boolean { - reload(properties[API_KEY_PROP]) - - if (SYMBOLS.isEmpty()) { - event.sendMessage(EMPTY_SYMBOLS_TABLE) - } else { - val nick = event.bot().nick - event.sendMessage("To convert from one currency to another:") - event.sendMessage(helpFormat(helpCmdSyntax("%c $CURRENCY_CMD 100 USD to EUR", nick, isPrivateMsgEnabled))) - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD 50,000 GBP to USD", nick, isPrivateMsgEnabled) - ) - ) - event.sendMessage("To list the supported currency codes:") - event.sendMessage( - helpFormat( - helpCmdSyntax("%c $CURRENCY_CMD $CODES_KEYWORD", nick, isPrivateMsgEnabled) - ) - ) - } - return true - } - - companion object { - /** - * The API Key property. - */ - const val API_KEY_PROP = "exchangerate-api-key" - - // Currency command - private const val CURRENCY_CMD = "currency" - - // Currency codes keyword - private const val CODES_KEYWORD = "codes" - - // Empty symbols table. - private const val EMPTY_SYMBOLS_TABLE = "Sorry, but the currency table is empty." - - // Currency symbols - private val SYMBOLS: TreeMap<String, String> = TreeMap() - - // Decimal format - private val DECIMAL_FORMAT = DecimalFormat("0.00#") - - /** - * Converts from a currency to another. - */ - @JvmStatic - fun convertCurrency(apiKey: String?, query: String): Message { - if (apiKey.isNullOrEmpty()) { - throw ModuleException("${CURRENCY_CMD}($query)", "No Exchange Rate API key specified.") - } - - val cmds = query.split(" ") - return if (cmds.size == 4) { - if (cmds[3] == cmds[1] || "0" == cmds[0]) { - PublicMessage("You're kidding, right?") - } else { - val to = cmds[1].uppercase() - val from = cmds[3].uppercase() - if (SYMBOLS.contains(to) && SYMBOLS.contains(from)) { - try { - val amt = cmds[0].replace(",", "") - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/pair/$to/$from/$amt") - val body = url.reader().body - val json = JSONObject(body) - - if (json.getString("result") == "success") { - val result = DECIMAL_FORMAT.format(json.getDouble("conversion_result")) - PublicMessage( - "${cmds[0]} ${SYMBOLS[to]} = $result ${SYMBOLS[from]}" - ) - } else { - ErrorMessage("Sorry, an error occurred while converting the currencies.") - } - } catch (ignore: IOException) { - ErrorMessage("Sorry, an IO error occurred while converting the currencies.") - } - } else { - ErrorMessage("Sounds like monopoly money to me!") - } - } - } else { - ErrorMessage("Invalid query. Let's try again.") - } - } - - /** - * Loads the currency ISO symbols. - */ - @JvmStatic - @Throws(ModuleException::class) - fun loadSymbols(apiKey: String?) { - if (!apiKey.isNullOrEmpty()) { - try { - val url = URL("https://v6.exchangerate-api.com/v6/$apiKey/codes") - val json = JSONObject(url.reader().body) - if (json.getString("result") == "success") { - val codes = json.getJSONArray("supported_codes") - for (i in 0 until codes.length()) { - val code = codes.getJSONArray(i) - SYMBOLS[code.getString(0)] = code.getString(1) - } - } - } catch (e: IOException) { - throw ModuleException( - "loadCodes(): IOE", - "An IO error has occurred while retrieving the currencies.", - e - ) - } - } - } - } - - init { - commands.add(CURRENCY_CMD) - initProperties(API_KEY_PROP) - loadSymbols(properties[ChatGpt2.API_KEY_PROP]) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt deleted file mode 100644 index 5c1dd09..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Dice.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Dice.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Dice module. - */ -class Dice : AbstractModule() { - override val name = "Dice" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val arg = if (args.isBlank()) "2d6" else args.trim() - val match = Regex("^([1-9]|[12]\\d|3[0-2])[dD]([1-9]|[12]\\d|3[0-2])$").find(arg) - if (match != null) { - val (dice, sides) = match.destructured - event.respond("you rolled " + roll(dice.toInt(), sides.toInt())) - } else { - helpResponse(event) - } - } - - companion object { - // Dice command - private const val DICE_CMD = "dice" - - @JvmStatic - fun roll(dice: Int, sides: Int): String { - val result = StringBuilder() - var total = 0 - - repeat(dice) { - val roll = (1..sides).random() - total += roll - - if (result.isNotEmpty()) { - result.append(" + ") - } - - result.append(roll.bold()) - } - - if (dice != 1) { - result.append(" = ${total.bold()}") - } - - return result.toString() - } - } - - init { - commands.add(DICE_CMD) - help.add("To roll 2 dice with 6 sides:") - help.add(helpFormat("%c $DICE_CMD [2d6]")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt deleted file mode 100644 index e85ea7b..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Gemini2.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Gemini2.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -class Gemini2 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Gemini2::class.java) - - override val name = GEMINI_NAME - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val answer = chat( - args.trim(), - properties[GEMINI_API_KEY], - properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() - ) - if (!answer.isNullOrEmpty()) { - event.sendMessage(answer) - } else { - event.respond("$name is stumped.") - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The service name. - */ - const val GEMINI_NAME = "Gemini" - - /** - * The API key - */ - const val GEMINI_API_KEY = "gemini-api-key" - - /** - * The max number of output tokens property. - */ - const val MAX_TOKENS_PROP = "gemini-max-tokens" - - // Gemini command - private const val GEMINI_CMD = "gemini" - - @JvmStatic - @Throws(ModuleException::class) - fun chat( - query: String, - apiKey: String?, - maxTokens: Int - ): String? { - if (!apiKey.isNullOrEmpty()) { - try { - val gemini = GoogleAiGeminiChatModel.builder() - .apiKey(apiKey) - .modelName("gemini-2.0-flash") - .maxOutputTokens(maxTokens) - .build() - - return gemini.generate(query) - } catch (e: Exception) { - throw ModuleException( - "$GEMINI_CMD($query): IO", - "An IO error has occurred while conversing with ${GEMINI_NAME}.", - e - ) - } - } else { - throw ModuleException("${GEMINI_CMD}($query)", "No $GEMINI_NAME Project ID or Location specified.") - } - } - } - - init { - commands.add(GEMINI_CMD) - with(help) { - add("To get answers from $name:") - add(Utils.helpFormat("%c $GEMINI_CMD <query>")) - add("For example:") - add(Utils.helpFormat("%c $GEMINI_CMD explain quantum computing in simple terms")) - add(Utils.helpFormat("%c $GEMINI_CMD how do I make an HTTP request in Javascript?")) - } - initProperties(GEMINI_API_KEY, MAX_TOKENS_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt deleted file mode 100644 index 26f3e71..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearch.kt +++ /dev/null @@ -1,162 +0,0 @@ -/* - * GoogleSearch.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.ReleaseInfo -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import org.json.JSONException -import org.json.JSONObject -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * The GoogleSearch module. - */ -class GoogleSearch : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(GoogleSearch::class.java) - - override val name = "GoogleSearch" - - /** - * Searches Google. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val results = searchGoogle( - args, - properties[API_KEY_PROP], - properties[CSE_KEY_PROP], - event.user.nick - ) - for (msg in results) { - if (msg.isError) { - event.respond(msg.msg.colorize(msg.color)) - } else { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - // Google API Key property - const val API_KEY_PROP = "google-api-key" - - // Google Custom Search Engine ID property - const val CSE_KEY_PROP = "google-cse-cx" - - // Google command - private const val GOOGLE_CMD = "google" - - /** - * Performs a search on Google. - */ - @JvmStatic - @Throws(ModuleException::class) - fun searchGoogle( - query: String, - apiKey: String?, - cseKey: String?, - quotaUser: String = ReleaseInfo.PROJECT - ): List<Message> { - if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { - throw ModuleException( - "${GoogleSearch::class.java.name} is disabled.", - "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." - ) - } - val results = mutableListOf<Message>() - if (query.isNotBlank()) { - try { - val url = URL( - "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + - ""aUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" - ) - val json = JSONObject(url.reader().body) - if (json.has("items")) { - val ja = json.getJSONArray("items") - for (i in 0 until ja.length()) { - val j = ja.getJSONObject(i) - results.add(NoticeMessage(j.getString("title").unescapeXml())) - results.add(NoticeMessage(helpFormat(j.getString("link"), false), Colors.DARK_GREEN)) - } - } else if (json.has("error")) { - val error = json.getJSONObject("error") - val message = error.getString("message") - throw ModuleException("searchGoogle($query): ${error.getInt("code")} : $message", message) - } else { - results.add(ErrorMessage("No results found.", Colors.RED)) - } - } catch (e: IOException) { - throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) - } catch (e: JSONException) { - throw ModuleException( - "searchGoogle($query): JSON", - "A JSON error has occurred searching Google.", - e - ) - } - } else { - results.add(ErrorMessage("Invalid query. Please try again.")) - } - return results - } - } - - init { - commands.add(GOOGLE_CMD) - help.add("To search Google:") - help.add(helpFormat("%c $GOOGLE_CMD <query>")) - initProperties(API_KEY_PROP, CSE_KEY_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt deleted file mode 100644 index e792ed4..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Joke.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Joke.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.jokeapi.exceptions.HttpErrorException -import net.thauvin.erik.jokeapi.exceptions.JokeException -import net.thauvin.erik.jokeapi.joke -import net.thauvin.erik.jokeapi.models.Type -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONException -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException - -/** - * The Joke module. - */ -class Joke : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Joke::class.java) - - override val name = "Joke" - - /** - * Returns a random joke from [JokeAPI](https://v2.jokeapi.dev/). - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - with(event.bot()) { - try { - randomJoke().forEach { - sendIRC().notice(channel, it.msg.colorize(it.color)) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } - } - - companion object { - // Joke command - private const val JOKE_CMD = "joke" - - /** - * Retrieves a random joke. - */ - @JvmStatic - @Throws(ModuleException::class) - fun randomJoke(): List<Message> { - return try { - val joke = joke(safe = true, type = Type.SINGLE, splitNewLine = true) - joke.joke.map { PublicMessage(it, Colors.CYAN) } - } catch (e: JokeException) { - throw ModuleException("randomJoke(): ${e.additionalInfo}", e.message, e) - } catch (e: HttpErrorException) { - throw ModuleException("randomJoke(): HTTP: ${e.statusCode}", e.message, e) - } catch (e: IOException) { - throw ModuleException("randomJoke(): IOE", "An IO error has occurred retrieving a random joke.", e) - } catch (e: JSONException) { - throw ModuleException("randomJoke(): JSON", "A parsing error has occurred retrieving a random joke.", e) - } - } - } - - init { - commands.add(JOKE_CMD) - help.add("To display a random joke:") - help.add(helpFormat("%c $JOKE_CMD")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt deleted file mode 100644 index f700757..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Lookup.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Lookup.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.apache.commons.net.whois.WhoisClient -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException - -/** - * The Lookup module. - */ -class Lookup : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Lookup::class.java) - - override val name = "Lookup" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.matches("(\\S.)+(\\S)+".toRegex())) { - try { - event.respondWith(nslookup(args).prependIndent()) - } catch (ignore: UnknownHostException) { - if (args.matches( - ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") - .toRegex() - ) - ) { - try { - val lines = whois(args) - if (lines.isNotEmpty()) { - var line: String - var hasData = false - for (rawLine in lines) { - line = rawLine.trim() - if (line.matches("^\\b(?!\\b[Cc]omment\\b)\\w+\\b: .*$".toRegex())) { - if (!hasData) { - event.respondWith(line) - hasData = true - } else { - event.bot().sendIRC().notice(event.user.nick, line) - } - } - } - } else { - event.respond("Unknown host.") - } - } catch (ioe: IOException) { - if (logger.isWarnEnabled) { - logger.warn("Unable to perform whois IP lookup: $args", ioe) - } - event.respond("Unable to perform whois IP lookup: ${ioe.message}") - } - } else { - event.respond("Unknown host.") - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The whois default host. - */ - const val WHOIS_HOST = "whois.arin.net" - - // Lookup command - private const val LOOKUP_CMD = "lookup" - - /** - * Performs a DNS lookup on the specified query. - */ - @JvmStatic - @Throws(UnknownHostException::class) - fun nslookup(query: String): String { - val buffer = StringBuilder() - val results = InetAddress.getAllByName(query) - var hostInfo: String - for (result in results) { - if (result.hostAddress == query) { - hostInfo = result.hostName - if (hostInfo == query) { - throw UnknownHostException() - } - } else { - hostInfo = result.hostAddress - } - if (buffer.isNotEmpty()) { - buffer.append(", ") - } - buffer.append(hostInfo) - } - return buffer.toString() - } - - /** - * Performs a whois IP query. - */ - @Throws(IOException::class) - private fun whois(query: String): List<String> { - return whois(query, WHOIS_HOST) - } - - /** - * Performs a whois IP query. - */ - @JvmStatic - @Throws(IOException::class) - fun whois(query: String, host: String): List<String> { - val whoisClient = WhoisClient() - val lines: List<String> - with(whoisClient) { - try { - defaultTimeout = Constants.CONNECT_TIMEOUT - connect(host) - soTimeout = Constants.CONNECT_TIMEOUT - setSoLinger(false, 0) - lines = if (WHOIS_HOST == host) { - query("n - $query").split("\n") - } else { - query(query).split("\n") - } - } finally { - disconnect() - } - } - return lines - } - } - - init { - commands.add(LOOKUP_CMD) - help.add("To perform a DNS lookup query:") - help.add(helpFormat("%c $LOOKUP_CMD <ip address or hostname>")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt deleted file mode 100644 index d4c2614..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Mastodon.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Mastodon.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.prefixIfMissing -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.social.SocialModule -import org.json.JSONException -import org.json.JSONObject -import org.json.JSONWriter -import java.io.IOException -import java.net.URI -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse - -class Mastodon : SocialModule() { - override val name = "Mastodon" - - override val handle: String? - get() = properties[HANDLE_PROP] - - override val isAutoPost: Boolean - get() = isEnabled && properties[AUTO_POST_PROP].toBoolean() - - override val isValidProperties: Boolean - get() = !(properties[INSTANCE_PROP].isNullOrBlank() || properties[ACCESS_TOKEN_PROP].isNullOrBlank()) - - /** - * Formats the entry for posting. - */ - override fun formatEntry(entry: EntryLink): String { - return "${entry.title} (via ${entry.nick} on ${entry.channel})${formatTags(entry)}\n\n${entry.link}" - } - - private fun formatTags(entry: EntryLink): String { - return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } - .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } - } - - /** - * Posts on Mastodon. - */ - @Throws(ModuleException::class) - override fun post(message: String, isDm: Boolean): String { - return toot( - apiKey = properties[ACCESS_TOKEN_PROP], - instance = properties[INSTANCE_PROP], - handle = handle, - message = message, - isDm = isDm - ) - } - - companion object { - // Property keys - const val ACCESS_TOKEN_PROP = "mastodon-access-token" - const val AUTO_POST_PROP = "mastodon-auto-post" - const val HANDLE_PROP = "mastodon-handle" - const val INSTANCE_PROP = "mastodon-instance" - - private const val MASTODON_CMD = "mastodon" - private const val TOOT_CMD = "toot" - - /** - * Post on Mastodon. - */ - @JvmStatic - @Throws(ModuleException::class) - fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { - val request = HttpRequest.newBuilder() - .uri(URI.create("https://$instance/api/v1/statuses")) - .header("Content-Type", "application/json") - .header("Authorization", "Bearer $apiKey") - .POST( - HttpRequest.BodyPublishers.ofString( - JSONWriter.valueToString( - if (isDm) { - mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") - } else { - mapOf("status" to message) - } - ) - ) - ) - .build() - try { - val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) - if (response.statusCode() == 200) { - return try { - val jsonResponse = JSONObject(response.body()) - if (isDm) { - jsonResponse.getString("content") - } else { - "Your message was posted to ${jsonResponse.getString("url")}" - } - } catch (e: JSONException) { - throw ModuleException("mastodonPost($message)", "A JSON error has occurred: ${e.message}", e) - } - } else { - throw IOException("Status Code: " + response.statusCode()) - } - } catch (e: IOException) { - throw ModuleException("mastodonPost($message)", "An IO error has occurred: ${e.message}", e) - } catch (e: InterruptedException) { - throw ModuleException("mastodonPost($message)", "An error has occurred: ${e.message}", e) - } - } - } - - init { - commands.add(MASTODON_CMD) - commands.add(TOOT_CMD) - help.add("To toot on Mastodon:") - help.add(Utils.helpFormat("%c $TOOT_CMD <message>")) - properties[AUTO_POST_PROP] = "false" - initProperties(ACCESS_TOKEN_PROP, HANDLE_PROP, INSTANCE_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt deleted file mode 100644 index 26d374a..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/ModuleException.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ModuleException.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -/** - * The `ModuleException` class. - */ -class ModuleException @JvmOverloads constructor( - val debugMessage: String, - message: String? = null, - cause: Throwable? = null -) : Exception(message, cause) { - companion object { - @Suppress("ConstPropertyName") - private const val serialVersionUID = 1L - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt deleted file mode 100644 index ca18216..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Ping.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Ping.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bot -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - -/** - * The Ping module. - */ -class Ping : AbstractModule() { - override val name = "Ping" - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - event.bot().sendIRC().action(channel, randomPing()) - } - - companion object { - /** - * The ping responses. - */ - @JvmField - val PINGS = listOf( - "is barely alive.", - "is trying to stay awake.", - "has gone fishing.", - "is somewhere over the rainbow.", - "has fallen and can't get up.", - "is running. You better go chase it.", - "has just spontaneously combusted.", - "is talking to itself... don't interrupt. That's rude.", - "is bartending at an AA meeting.", - "is hibernating.", - "is saving energy: apathetic mode activated.", - "is busy. Go away!" - ) - - @JvmStatic - fun randomPing(): String { - return PINGS[PINGS.indices.random()] - } - - /** - * The ping command. - */ - private const val PING_CMD = "ping" - } - - init { - commands.add(PING_CMD) - help.add("To ping the bot:") - help.add(helpFormat("%c $PING_CMD")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt deleted file mode 100644 index b8c81f1..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissors.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * RockPaperScissors.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent - - -/** - * Simple module example in Kotlin. - */ -class RockPaperScissors : AbstractModule() { - override val name = "RockPaperScissors" - - init { - with(commands) { - add(Hands.ROCK.name.lowercase()) - add(Hands.PAPER.name.lowercase()) - add(Hands.SCISSORS.name.lowercase()) - } - - with(help) { - add("To play Rock Paper Scissors:") - add( - helpFormat( - "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" - + " | ${Hands.SCISSORS.name.lowercase()}" - ) - ) - } - } - - enum class Hands(val action: String) { - ROCK("crushes") { - override fun beats(hand: Hands): Boolean { - return hand == SCISSORS - } - }, - PAPER("covers") { - override fun beats(hand: Hands): Boolean { - return hand == ROCK - } - }, - SCISSORS("cuts") { - override fun beats(hand: Hands): Boolean { - return hand == PAPER - } - }; - - abstract fun beats(hand: Hands): Boolean - } - - companion object { - // For testing. - fun winLoseOrDraw(player: String, bot: String): String { - val hand = Hands.valueOf(player.uppercase()) - val botHand = Hands.valueOf(bot.uppercase()) - - return when { - hand == botHand -> "draw" - hand.beats(botHand) -> "win" - else -> "lose" - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - val hand = Hands.valueOf(cmd.uppercase()) - val botHand = Hands.entries[(0..Hands.entries.size).random()] - when { - hand == botHand -> { - event.respond("${hand.name} vs. ${botHand.name} » You ${"tie".bold()}.") - } - - hand.beats(botHand) -> { - event.respond("${hand.name.bold()} ${hand.action} ${botHand.name} » You ${"win".bold()}!") - } - - else -> { - event.respond("${botHand.name.bold()} ${botHand.action} ${hand.name} » You ${"lose".bold()}!") - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt deleted file mode 100644 index d71c91a..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/StockQuote.kt +++ /dev/null @@ -1,236 +0,0 @@ -/* - * StockQuote.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.json.JSONException -import org.json.JSONObject -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -/** - * The StockQuote module. - */ -class StockQuote : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(StockQuote::class.java) - - override val name = "StockQuote" - - /** - * Returns the specified stock quote from Alpha Vantage. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getQuote(args, properties[API_KEY_PROP]) - for (msg in messages) { - event.sendMessage(channel, msg) - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The API property key. - */ - const val API_KEY_PROP = "alphavantage-api-key" - - /** - * The Invalid Symbol error string. - */ - const val INVALID_SYMBOL = "Invalid symbol." - - // API URL - private const val API_URL = "https://www.alphavantage.co/query?function=" - - // Quote command - private const val STOCK_CMD = "stock" - - @Throws(ModuleException::class) - private fun getJsonResponse(response: String, debugMessage: String): JSONObject { - return if (response.isNotBlank()) { - val json = JSONObject(response) - try { - val info = json.getString("Information") - if (info.isNotEmpty()) { - throw ModuleException(debugMessage, info.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - try { - var error = json.getString("Note") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - error = json.getString("Error Message") - if (error.isNotEmpty()) { - throw ModuleException(debugMessage, error.unescapeXml()) - } - } catch (ignore: JSONException) { - // Do nothing - } - json - } else { - throw ModuleException(debugMessage, "Empty Response.") - } - } - - /** - * Retrieves a stock quote. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getQuote(symbol: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${StockQuote::class.java.name} is disabled.", - "${STOCK_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val messages = mutableListOf<Message>() - if (symbol.isNotBlank()) { - val debugMessage = "getQuote($symbol)" - var response: String - try { - with(messages) { - // Search for symbol/keywords - response = URL( - "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - var json = getJsonResponse(response, debugMessage) - val symbols = json.getJSONArray("bestMatches") - if (symbols.isEmpty) { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } else { - val symbolInfo = symbols.getJSONObject(0) - - // Get quote for symbol - response = URL( - "${API_URL}GLOBAL_QUOTE&symbol=" - + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" - + apiKey.encodeUrl() - ).reader().body - json = getJsonResponse(response, debugMessage) - val quote = json.getJSONObject("Global Quote") - if (quote.isEmpty) { - add(ErrorMessage(INVALID_SYMBOL)) - } else { - - add( - PublicMessage( - "Symbol: " + quote.getString("01. symbol").unescapeXml() - + " [" + symbolInfo.getString("2. name").unescapeXml() + ']' - ) - ) - - val pad = 10 - - add( - PublicMessage( - "Price:".padEnd(pad).prependIndent() - + quote.getString("05. price").unescapeXml() - ) - ) - add( - PublicMessage( - "Previous:".padEnd(pad).prependIndent() - + quote.getString("08. previous close").unescapeXml() - ) - ) - - val data = arrayOf( - "Open" to "02. open", - "High" to "03. high", - "Low" to "04. low", - "Volume" to "06. volume", - "Latest" to "07. latest trading day" - ) - - data.forEach { - add( - NoticeMessage( - "${it.first}:".padEnd(pad).prependIndent() - + quote.getString(it.second).unescapeXml() - ) - ) - } - - add( - NoticeMessage( - "Change:".padEnd(pad).prependIndent() - + quote.getString("09. change").unescapeXml() - + " [" + quote.getString("10. change percent").unescapeXml() + ']' - ) - ) - } - } - } - } catch (e: IOException) { - throw ModuleException("$debugMessage: IOE", "An IO error has occurred retrieving a stock quote.", e) - } catch (e: NullPointerException) { - throw ModuleException("$debugMessage: NPE", "An error has occurred retrieving a stock quote.", e) - } - } else { - messages.add(ErrorMessage(INVALID_SYMBOL)) - } - return messages - } - } - - init { - commands.add(STOCK_CMD) - help.add("To retrieve a stock quote:") - help.add(helpFormat("%c $STOCK_CMD <symbol|keywords>")) - initProperties(API_KEY_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt deleted file mode 100644 index 70ac4ec..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/War.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * War.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import org.pircbotx.hooks.types.GenericMessageEvent -import java.security.SecureRandom - -/** - * The War module. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @since 1.0 - */ -class War : AbstractModule() { - override val name = "War" - - override fun commandResponse( - channel: String, cmd: String, args: String, - event: GenericMessageEvent - ) { - var i: Int - var y: Int - do { - i = RANDOM.nextInt(HEARTS.size) - y = RANDOM.nextInt(HEARTS.size) - val result: String = if (i < y) { - "win".bold() - } else if (i > y) { - "lose".bold() - } else { - "tie".bold() + ". This means " + "WAR".bold() - } - event.respond( - DECK[RANDOM.nextInt(DECK.size)][i] + " " + DECK[RANDOM.nextInt(DECK.size)][y] + - " » You " + result + '!' - ) - } while (i == y) - } - - companion object { - private val CLUBS = arrayOf("🃑", "🃞", "🃝", "🃛", "🃚", "🃙", "🃘", "🃗", "🃖", "🃕", "🃔", "🃓", "🃒") - private val DIAMONDS = arrayOf("🃁", "🃎", "🃍", "🃋", "🃊", "🃉", "🃈", "🃇", "🃆", "🃅", "🃄", "🃃", "🃂") - private val HEARTS = arrayOf("🂱", "🂾", "🂽", "🂻", "🂺", "🂹", "🂸", "🂷", "🂶", "🂵", "🂴", "🂳", "🂲") - - // Random - private val RANDOM = SecureRandom() - private val SPADES = arrayOf("🂡", "🂮", "🂭", "🂫", "🂪", "🂩", "🂨", "🂧", "🂦", "🂥", "🂤", "🂣", "🂢") - private val DECK = arrayOf(HEARTS, SPADES, DIAMONDS, CLUBS) - - // War command - private const val WAR_CMD = "war" - } - - init { - commands.add(WAR_CMD) - help.add("To play war:") - help.add(helpFormat("%c $WAR_CMD")) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt deleted file mode 100644 index 074edd0..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/Weather2.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Weather2.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.aksingh.owmjapis.api.APIException -import net.aksingh.owmjapis.core.OWM -import net.aksingh.owmjapis.core.OWM.Country -import net.aksingh.owmjapis.model.CurrentWeather -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.capitalizeWords -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendMessage -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.NoticeMessage -import net.thauvin.erik.mobibot.msg.PublicMessage -import org.pircbotx.Colors -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import kotlin.math.roundToInt - -/** - * The `Weather2` module. - */ -class Weather2 : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(Weather2::class.java) - - override val name = "Weather" - - /** - * Fetches the weather data from a specific city. - */ - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val messages = getWeather(args, properties[API_KEY_PROP]) - if (messages[0].isError) { - helpResponse(event) - } else { - for (msg in messages) { - event.sendMessage(channel, msg) - } - } - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The OpenWeatherMap API Key property. - */ - const val API_KEY_PROP = "owm-api-key" - - // Weather command - private const val WEATHER_CMD = "weather" - - /** - * Converts and rounds temperature from °F to °C. - */ - fun ftoC(d: Double): Pair<Int, Int> { - val c = (d - 32) * 5 / 9 - return d.roundToInt() to c.roundToInt() - } - - /** - * Returns a country based on its country code. Defaults to [Country.UNITED_STATES] if not found. - */ - fun getCountry(countryCode: String): Country { - for (c in Country.entries) { - if (c.value.equals(countryCode, ignoreCase = true)) { - return c - } - } - return Country.UNITED_STATES - } - - /** - * Retrieves the weather data. - */ - @JvmStatic - @Throws(ModuleException::class) - fun getWeather(query: String, apiKey: String?): List<Message> { - if (apiKey.isNullOrBlank()) { - throw ModuleException( - "${Weather2::class.java.name} is disabled.", - "${WEATHER_CMD.capitalise()} is disabled. The API key is missing." - ) - } - val owm = OWM(apiKey) - val messages = mutableListOf<Message>() - owm.unit = OWM.Unit.IMPERIAL - if (query.isNotBlank()) { - val argv = query.split(",") - if (argv.size in 1..2) { - val city = argv[0].trim() - val code: String = if (argv.size > 1 && argv[1].isNotBlank()) { - argv[1].trim() - } else { - "US" - } - try { - val country = getCountry(code) - val cwd: CurrentWeather = if (city.matches("\\d+".toRegex())) { - owm.currentWeatherByZipCode(city.toInt(), country) - } else { - owm.currentWeatherByCityName(city, country) - } - if (cwd.hasCityName()) { - messages.add( - PublicMessage( - "City: ${cwd.cityName}, " + - country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" - ) - ) - cwd.mainData?.let { - with(it) { - if (hasTemp()) { - temp?.let { t -> - val (f, c) = ftoC(t) - messages.add(PublicMessage("Temperature: ${f}°F, ${c}°C")) - } - } - if (hasHumidity()) { - humidity?.let { h -> - messages.add(NoticeMessage("Humidity: ${h.roundToInt()}%")) - } - } - } - } - if (cwd.hasWindData()) { - cwd.windData?.let { - if (it.hasSpeed()) { - it.speed?.let { s -> - val w = mphToKmh(s) - messages.add(NoticeMessage("Wind: ${w.first} mph, ${w.second} km/h")) - } - } - } - } - if (cwd.hasWeatherList()) { - val condition = StringBuilder("Condition:") - cwd.weatherList?.let { - for (w in it) { - w?.let { - condition.append(' ') - .append(w.getDescription().capitalise()) - .append('.') - } - } - messages.add(NoticeMessage(condition.toString())) - } - } - if (cwd.hasCityId()) { - cwd.cityId?.let { - if (it > 0) { - messages.add( - NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) - ) - } else { - messages.add( - NoticeMessage( - "https://openweathermap.org/find?q=" - + "$city,${code.uppercase()}".encodeUrl(), - Colors.GREEN - ) - ) - } - } - } - } - } catch (e: APIException) { - if (e.code == 404) { - throw ModuleException( - "getWeather($query): API ${e.code}", - "The requested city was not found.", - e - ) - } else { - throw ModuleException("getWeather($query): API ${e.code}", e.message, e) - } - } catch (e: NullPointerException) { - throw ModuleException("getWeather($query): NPE", "Unable to perform weather lookup.", e) - } - } - } - if (messages.isEmpty()) { - messages.add(ErrorMessage("Invalid syntax.")) - } - return messages - } - - /** - * Converts and rounds temperature from mph to km/h. - */ - fun mphToKmh(w: Double): Pair<Int, Int> { - val kmh = w * 1.60934 - return w.roundToInt() to kmh.roundToInt() - } - } - - init { - commands.add(WEATHER_CMD) - with(help) { - add("To display weather information:") - add(helpFormat("%c $WEATHER_CMD <city> [, <country code>]")) - add("For example:") - add(helpFormat("%c $WEATHER_CMD paris, fr")) - add("The default ISO 3166 country code is ${"US".bold()}. Zip codes supported in most countries.") - } - initProperties(API_KEY_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt deleted file mode 100644 index 2e2e7ec..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WolframAlpha.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * WolframAlpha.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.isHttpSuccess -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.io.IOException -import java.net.URL - -class WolframAlpha : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(WolframAlpha::class.java) - - override val name = "WolframAlpha" - - private fun getUnits(unit: String?): String { - return if (unit?.lowercase() == METRIC) { - METRIC - } else { - IMPERIAL - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.isNotBlank()) { - try { - val query = args.trim().split("units=", limit = 2, ignoreCase = true) - event.sendMessage( - queryWolfram( - query[0].trim(), - units = if (query.size == 2) { - getUnits(query[1].trim()) - } else { - getUnits(properties[UNITS_PROP]) - }, - appId = properties[APPID_KEY_PROP] - ) - ) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } else { - helpResponse(event) - } - } - - companion object { - /** - * The Wolfram Alpha API Key property. - */ - const val APPID_KEY_PROP = "wolfram-appid" - - /** - * The Wolfram units properties - */ - const val UNITS_PROP = "wolfram-units" - - const val METRIC = "metric" - const val IMPERIAL = "imperial" - - // Wolfram command - private const val WOLFRAM_CMD = "wolfram" - - // Wolfram Alpha API URL - private const val API_URL = "http://api.wolframalpha.com/v1/spoken?appid=" - - @JvmStatic - @Throws(ModuleException::class) - fun queryWolfram(query: String, units: String = IMPERIAL, appId: String?): String { - if (!appId.isNullOrEmpty()) { - try { - val urlReader = URL("${API_URL}${appId}&units=${units}&i=" + query.encodeUrl()).reader() - if (urlReader.responseCode.isHttpSuccess()) { - return urlReader.body - } else { - throw ModuleException( - "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", - urlReader.body.ifEmpty { - "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" - } - ) - } - } catch (ioe: IOException) { - throw ModuleException( - "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe - ) - } - } else { - throw ModuleException("wolfram($query): No API Key", "No Wolfram Alpha API key specified.") - } - } - } - - init { - commands.add(WOLFRAM_CMD) - with(help) { - add("To get answers from Wolfram Alpha:") - add(Utils.helpFormat("%c $WOLFRAM_CMD <query> [units=(${METRIC}|${IMPERIAL})]")) - add("For example:") - add(Utils.helpFormat("%c $WOLFRAM_CMD days until christmas")) - add(Utils.helpFormat("%c $WOLFRAM_CMD distance earth moon units=metric")) - } - initProperties(APPID_KEY_PROP, UNITS_PROP) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt b/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt deleted file mode 100644 index afc0a5f..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/modules/WorldTime.kt +++ /dev/null @@ -1,390 +0,0 @@ -/* - * WorldTime.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.sendList -import net.thauvin.erik.mobibot.Utils.sendMessage -import org.pircbotx.hooks.types.GenericMessageEvent -import java.time.ZoneId -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.time.temporal.ChronoField - -/** - * The WorldTime module. - */ -class WorldTime : AbstractModule() { - override val name = "WorldTime" - - companion object { - /** - * Beats (Internet Time) keyword - */ - const val BEATS_KEYWORD = ".beats" - - /** - * Supported countries - */ - val COUNTRIES_MAP = buildMap<String, String> { - put("AG", "America/Antigua") - put("AI", "America/Anguilla") - put("AE", "Asia/Dubai") - put("AD", "Europe/Andorra") - put("AKDT", "America/Anchorage") - put("AF", "Asia/Kabul") - put("AKST", "America/Anchorage") - put("AL", "Europe/Tirane") - put("AM", "Asia/Yerevan") - put("AO", "Africa/Luanda") - put("AQ", "Antarctica/South_Pole") - put("AR", "America/Argentina/Buenos_Aires") - put("AS", "Pacific/Pago_Pago") - put("AT", "Europe/Vienna") - put("AU", "Australia/Sydney") - put("AW", "America/Aruba") - put("AX", "Europe/Mariehamn") - put("AZ", "Asia/Baku") - put("BA", "Europe/Sarajevo") - put("BB", "America/Barbados") - put("BD", "Asia/Dhaka") - put("BE", "Europe/Brussels") - put("BEAT", BEATS_KEYWORD) - put("BF", "Africa/Ouagadougou") - put("BG", "Europe/Sofia") - put("BH", "Asia/Bahrain") - put("BI", "Africa/Bujumbura") - put("BJ", "Africa/Porto-Novo") - put("BL", "America/St_Barthelemy") - put("BM", "Atlantic/Bermuda") - put("BMT", BEATS_KEYWORD) - put("BN", "Asia/Brunei") - put("BO", "America/La_Paz") - put("BQ", "America/Kralendijk") - put("BR", "America/Sao_Paulo") - put("BS", "America/Nassau") - put("BT", "Asia/Thimphu") - put("BW", "Africa/Gaborone") - put("BY", "Europe/Minsk") - put("BZ", "America/Belize") - put("CA", "America/Montreal") - put("CC", "Indian/Cocos") - put("CD", "Africa/Kinshasa") - put("CDT", "America/Chicago") - put("CET", "CET") - put("CF", "Africa/Bangui") - put("CG", "Africa/Brazzaville") - put("CH", "Europe/Zurich") - put("CI", "Africa/Abidjan") - put("CK", "Pacific/Rarotonga") - put("CL", "America/Santiago") - put("CM", "Africa/Douala") - put("CN", "Asia/Shanghai") - put("CO", "America/Bogota") - put("CR", "America/Costa_Rica") - put("CST", "America/Chicago") - put("CU", "Cuba") - put("CV", "Atlantic/Cape_Verde") - put("CW", "America/Curacao") - put("CX", "Indian/Christmas") - put("CY", "Asia/Nicosia") - put("CZ", "Europe/Prague") - put("DE", "Europe/Berlin") - put("DJ", "Africa/Djibouti") - put("DK", "Europe/Copenhagen") - put("DM", "America/Dominica") - put("DO", "America/Santo_Domingo") - put("DZ", "Africa/Algiers") - put("EC", "Pacific/Galapagos") - put("EDT", "America/New_York") - put("EE", "Europe/Tallinn") - put("EG", "Africa/Cairo") - put("EH", "Africa/El_Aaiun") - put("ER", "Africa/Asmara") - put("ES", "Europe/Madrid") - put("EST", "America/New_York") - put("ET", "Africa/Addis_Ababa") - put("FI", "Europe/Helsinki") - put("FJ", "Pacific/Fiji") - put("FK", "Atlantic/Stanley") - put("FM", "Pacific/Yap") - put("FO", "Atlantic/Faroe") - put("FR", "Europe/Paris") - put("GA", "Africa/Libreville") - put("GB", "Europe/London") - put("GD", "America/Grenada") - put("GE", "Asia/Tbilisi") - put("GF", "America/Cayenne") - put("GG", "Europe/Guernsey") - put("GH", "Africa/Accra") - put("GI", "Europe/Gibraltar") - put("GL", "America/Thule") - put("GM", "Africa/Banjul") - put("GMT", "GMT") - put("GN", "Africa/Conakry") - put("GP", "America/Guadeloupe") - put("GQ", "Africa/Malabo") - put("GR", "Europe/Athens") - put("GS", "Atlantic/South_Georgia") - put("GT", "America/Guatemala") - put("GU", "Pacific/Guam") - put("GW", "Africa/Bissau") - put("GY", "America/Guyana") - put("HK", "Asia/Hong_Kong") - put("HN", "America/Tegucigalpa") - put("HR", "Europe/Zagreb") - put("HST", "Pacific/Honolulu") - put("HT", "America/Port-au-Prince") - put("HU", "Europe/Budapest") - put("ID", "Asia/Jakarta") - put("IE", "Europe/Dublin") - put("IL", "Asia/Tel_Aviv") - put("IM", "Europe/Isle_of_Man") - put("IN", "Asia/Kolkata") - put("IO", "Indian/Chagos") - put("IQ", "Asia/Baghdad") - put("IR", "Asia/Tehran") - put("IS", "Atlantic/Reykjavik") - put("IT", "Europe/Rome") - put("JE", "Europe/Jersey") - put("JM", "Jamaica") - put("JO", "Asia/Amman") - put("JP", "Asia/Tokyo") - put("KE", "Africa/Nairobi") - put("KG", "Asia/Bishkek") - put("KH", "Asia/Phnom_Penh") - put("KI", "Pacific/Tarawa") - put("KM", "Indian/Comoro") - put("KN", "America/St_Kitts") - put("KP", "Asia/Pyongyang") - put("KR", "Asia/Seoul") - put("KW", "Asia/Riyadh") - put("KY", "America/Cayman") - put("KZ", "Asia/Oral") - put("LA", "Asia/Vientiane") - put("LB", "Asia/Beirut") - put("LC", "America/St_Lucia") - put("LI", "Europe/Vaduz") - put("LK", "Asia/Colombo") - put("LR", "Africa/Monrovia") - put("LS", "Africa/Maseru") - put("LT", "Europe/Vilnius") - put("LU", "Europe/Luxembourg") - put("LV", "Europe/Riga") - put("LY", "Africa/Tripoli") - put("MA", "Africa/Casablanca") - put("MC", "Europe/Monaco") - put("MD", "Europe/Chisinau") - put("MDT", "America/Denver") - put("ME", "Europe/Podgorica") - put("MF", "America/Marigot") - put("MG", "Indian/Antananarivo") - put("MH", "Pacific/Majuro") - put("MK", "Europe/Skopje") - put("ML", "Africa/Timbuktu") - put("MM", "Asia/Yangon") - put("MN", "Asia/Ulaanbaatar") - put("MO", "Asia/Macau") - put("MP", "Pacific/Saipan") - put("MQ", "America/Martinique") - put("MR", "Africa/Nouakchott") - put("MS", "America/Montserrat") - put("MST", "America/Denver") - put("MT", "Europe/Malta") - put("MU", "Indian/Mauritius") - put("MV", "Indian/Maldives") - put("MW", "Africa/Blantyre") - put("MX", "America/Mexico_City") - put("MY", "Asia/Kuala_Lumpur") - put("MZ", "Africa/Maputo") - put("NA", "Africa/Windhoek") - put("NC", "Pacific/Noumea") - put("NE", "Africa/Niamey") - put("NF", "Pacific/Norfolk") - put("NG", "Africa/Lagos") - put("NI", "America/Managua") - put("NL", "Europe/Amsterdam") - put("NO", "Europe/Oslo") - put("NP", "Asia/Kathmandu") - put("NR", "Pacific/Nauru") - put("NU", "Pacific/Niue") - put("NZ", "Pacific/Auckland") - put("OM", "Asia/Muscat") - put("PA", "America/Panama") - put("PDT", "America/Los_Angeles") - put("PE", "America/Lima") - put("PF", "Pacific/Tahiti") - put("PG", "Pacific/Port_Moresby") - put("PH", "Asia/Manila") - put("PK", "Asia/Karachi") - put("PL", "Europe/Warsaw") - put("PM", "America/Miquelon") - put("PN", "Pacific/Pitcairn") - put("PR", "America/Puerto_Rico") - put("PS", "Asia/Gaza") - put("PST", "America/Los_Angeles") - put("PT", "Europe/Lisbon") - put("PW", "Pacific/Palau") - put("PY", "America/Asuncion") - put("QA", "Asia/Qatar") - put("RE", "Indian/Reunion") - put("RO", "Europe/Bucharest") - put("RS", "Europe/Belgrade") - put("RU", "Europe/Moscow") - put("RW", "Africa/Kigali") - put("SA", "Asia/Riyadh") - put("SB", "Pacific/Guadalcanal") - put("SC", "Indian/Mahe") - put("SD", "Africa/Khartoum") - put("SE", "Europe/Stockholm") - put("SG", "Asia/Singapore") - put("SH", "Atlantic/St_Helena") - put("SI", "Europe/Ljubljana") - put("SJ", "Atlantic/Jan_Mayen") - put("SK", "Europe/Bratislava") - put("SL", "Africa/Freetown") - put("SM", "Europe/San_Marino") - put("SN", "Africa/Dakar") - put("SO", "Africa/Mogadishu") - put("SR", "America/Paramaribo") - put("SS", "Africa/Juba") - put("ST", "Africa/Sao_Tome") - put("SV", "America/El_Salvador") - put("SX", "America/Lower_Princes") - put("SY", "Asia/Damascus") - put("SZ", "Africa/Mbabane") - put("TC", "America/Grand_Turk") - put("TD", "Africa/Ndjamena") - put("TF", "Indian/Kerguelen") - put("TG", "Africa/Lome") - put("TH", "Asia/Bangkok") - put("TJ", "Asia/Dushanbe") - put("TK", "Pacific/Fakaofo") - put("TL", "Asia/Dili") - put("TM", "Asia/Ashgabat") - put("TN", "Africa/Tunis") - put("TO", "Pacific/Tongatapu") - put("TR", "Europe/Istanbul") - put("TT", "America/Port_of_Spain") - put("TV", "Pacific/Funafuti") - put("TW", "Asia/Taipei") - put("TZ", "Africa/Dar_es_Salaam") - put("UA", "Europe/Kiev") - put("UG", "Africa/Kampala") - put("UK", "Europe/London") - put("UM", "Pacific/Wake") - put("US", "America/New_York") - put("UTC", "UTC") - put("UY", "America/Montevideo") - put("UZ", "Asia/Tashkent") - put("VA", "Europe/Vatican") - put("VC", "America/St_Vincent") - put("VE", "America/Caracas") - put("VG", "America/Tortola") - put("VI", "America/St_Thomas") - put("VN", "Asia/Ho_Chi_Minh") - put("VU", "Pacific/Efate") - put("WF", "Pacific/Wallis") - put("WS", "Pacific/Apia") - put("YE", "Asia/Aden") - put("YT", "Indian/Mayotte") - put("ZA", "Africa/Johannesburg") - put("ZM", "Africa/Lusaka") - put("ZULU", "Zulu") - put("ZW", "Africa/Harare") - ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } - .forEach { tz -> put(tz, tz) } - } - - // The Time command - private const val TIME_CMD = "time" - - // The zones arguments - private const val ZONES_ARGS = "zones" - - // The default zone - private const val DEFAULT_ZONE = "PST" - - // Date/Time Format - private var dtf = - DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") - - /** - * Returns the current Internet (beat) Time. - */ - private fun internetTime(): String { - val zdt = ZonedDateTime.now(ZoneId.of("UTC+01:00")) - val beats = ((zdt[ChronoField.SECOND_OF_MINUTE] + zdt[ChronoField.MINUTE_OF_HOUR] * 60 - + zdt[ChronoField.HOUR_OF_DAY] * 3600) / 86.4).toInt() - return "%c%03d".format('@', beats) - } - - /** - * Returns the time for the given timezone/city. - */ - @JvmStatic - fun time(query: String = DEFAULT_ZONE): String { - val tz = COUNTRIES_MAP[(if (query.isNotBlank()) query.trim().uppercase() else DEFAULT_ZONE)] - return if (tz != null) { - if (BEATS_KEYWORD == tz) { - "The current Internet Time is ${internetTime().bold()} $BEATS_KEYWORD" - } else { - (ZonedDateTime.now().withZoneSameInstant(ZoneId.of(tz)).format(dtf) - + tz.substring(tz.lastIndexOf('/') + 1).replace('_', ' ').bold()) - } - } else { - "Unsupported country/zone. Please try again." - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - if (args.equals(ZONES_ARGS, true)) { - event.sendMessage("The supported countries/zones are: ") - event.sendList(COUNTRIES_MAP.keys.sorted().map { it.padEnd(4) }, 14, isIndent = true) - } else { - event.respond(time(args)) - } - } - - override val isPrivateMsgEnabled = true - - init { - with(help) { - add("To display a country's current date/time:") - add(helpFormat("%c $TIME_CMD [<country code or zone>]")) - add("For a listing of the supported countries/zones:") - add(helpFormat("%c $TIME_CMD $ZONES_ARGS")) - } - commands.add(TIME_CMD) - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt deleted file mode 100644 index 56e7b92..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/ErrorMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ErrorMessage.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -/** - * The `ErrorMessage` class. - */ -class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isError = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt deleted file mode 100644 index 1a6e58b..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/Message.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Message.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -/** - * The `Message` class. - */ -open class Message @JvmOverloads constructor( - var msg: String, - var color: String = DEFAULT_COLOR, - var isNotice: Boolean = false, - isError: Boolean = false, - var isPrivate: Boolean = false -) { - companion object { - var DEFAULT_COLOR = "" - } - - init { - if (isError) { - isNotice = true - } - } - - /** Error flag. */ - var isError = isError - set(value) { - if (value) isNotice = true - field = value - } - - override fun toString(): String { - return "Message(color='$color', isError=$isError, isNotice=$isNotice, isPrivate=$isPrivate, msg='$msg')" - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt deleted file mode 100644 index f06ce89..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/NoticeMessage.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * NoticeMessage.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -/** - * The `NoticeMessage` class. - */ -class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isNotice = true) - diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt deleted file mode 100644 index ef0eeb1..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PrivateMessage.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * PrivateMessage.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -/** - * The `PrivateMessage` class. - */ -class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : - Message(msg, color, isPrivate = true) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt b/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt deleted file mode 100644 index be6583f..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/msg/PublicMessage.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * PublicMessage.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -/** - * The `PublicMessage` class. - */ -class PublicMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : Message(msg, color) diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt deleted file mode 100644 index de9653d..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialManager.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * SocialManager.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.social - -import net.thauvin.erik.mobibot.Addons -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import java.util.* - -/** - * Social Manager. - */ -class SocialManager { - private val entries: MutableSet<Int> = HashSet() - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - private val modules = ArrayList<SocialModule>() - private val timer = Timer(true) - - /** - * Adds social modules. - */ - fun add(addons: Addons, vararg modules: SocialModule) { - modules.forEach { - if (addons.add(it)) { - this.modules.add(it) - } - } - } - - /** - * Returns the number of entries. - */ - fun entriesCount(): Int = entries.size - - /** - * Sends a social notification (dm, etc.) - */ - fun notification(msg: String) { - modules.forEach { - it.notification(msg) - } - } - - /** - * Posts to social media. - */ - fun postEntry(index: Int) { - if (entries.contains(index)) { - modules.forEach { - it.postEntry(index) - } - entries.remove(index) - } - } - - /** - * Queues an entry for posting to social media. - */ - fun queueEntry(index: Int) { - if (modules.isNotEmpty()) { - entries.add(index) - if (logger.isDebugEnabled) { - logger.debug("Scheduling {} for posting on social media.", index.toLinkLabel()) - } - timer.schedule(SocialTimer(this, index), Constants.TIMER_DELAY * 60L * 1000L) - } - } - - /** - * Removes entries from queue. - */ - fun removeEntry(index: Int) { - entries.remove(index) - } - - /** - * Posts all entries on shutdown. - */ - fun shutdown() { - timer.cancel() - entries.forEach { - postEntry(it) - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt deleted file mode 100644 index d45cf5c..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialModule.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SocialModule.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.social - -import net.thauvin.erik.mobibot.commands.links.LinksManager -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import net.thauvin.erik.mobibot.entries.EntryLink -import net.thauvin.erik.mobibot.modules.AbstractModule -import net.thauvin.erik.mobibot.modules.ModuleException -import org.pircbotx.hooks.types.GenericMessageEvent -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -abstract class SocialModule : AbstractModule() { - private val logger: Logger = LoggerFactory.getLogger(SocialManager::class.java) - - abstract val handle: String? - abstract val isAutoPost: Boolean - - abstract fun formatEntry(entry: EntryLink): String - - /** - * Sends a DM. - */ - fun notification(msg: String) { - if (isEnabled && !handle.isNullOrBlank()) { - try { - post(message = msg, isDm = true) - if (logger.isDebugEnabled) logger.debug("Notified $handle on $name: $msg") - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn("Failed to notify $handle on $name: $msg", e) - } - } - } - - abstract fun post(message: String, isDm: Boolean): String - - /** - * Post entry to social media. - */ - fun postEntry(index: Int) { - if (isAutoPost && LinksManager.entries.links.size >= index) { - try { - if (logger.isDebugEnabled) { - logger.debug("Posting {} to $name.", index.toLinkLabel()) - } - post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn( - "Failed to post entry ${index.toLinkLabel()} on $name.", - e - ) - } - } - } - - override fun commandResponse(channel: String, cmd: String, args: String, event: GenericMessageEvent) { - try { - event.respond(post("$args (by ${event.user.nick} on $channel)", false)) - } catch (e: ModuleException) { - if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) - e.message?.let { - event.respond(it) - } - } - } -} diff --git a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt b/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt deleted file mode 100644 index aadebf5..0000000 --- a/src/main/kotlin/net/thauvin/erik/mobibot/social/SocialTimer.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SocialTimer.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.social - -import java.util.* - -class SocialTimer(private var socialManager: SocialManager, private var index: Int) : TimerTask() { - override fun run() { - socialManager.postEntry(index) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt deleted file mode 100644 index 27163fb..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/AddonsTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * AddonsTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import assertk.assertThat -import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import assertk.assertions.size -import net.thauvin.erik.mobibot.commands.ChannelFeed -import net.thauvin.erik.mobibot.commands.Cycle -import net.thauvin.erik.mobibot.commands.Die -import net.thauvin.erik.mobibot.commands.Ignore -import net.thauvin.erik.mobibot.commands.links.Comment -import net.thauvin.erik.mobibot.commands.links.View -import net.thauvin.erik.mobibot.modules.* -import java.util.* -import kotlin.test.Test - -class AddonsTest { - private val p = Properties().apply { - put("disabled-modules", "war,dice Lookup") - put("disabled-commands", "View | comment") - } - private val addons = Addons(p) - - @Test - fun addTest() { - // Modules - addons.add(Joke()) - addons.add(RockPaperScissors()) - addons.add(War()) - addons.add(Dice()) - addons.add(Lookup()) - assertThat(addons::modules).size().isEqualTo(2) - assertThat(addons.names.modules, "names.modules").containsExactly("Joke", "RockPaperScissors") - - // Commands - addons.add(View()) - addons.add(Comment()) - addons.add(Cycle()) - addons.add(Die()) // invisible - addons.add(ChannelFeed("channel")) // no properties, disabled - p[Ignore.IGNORE_PROP] = "nick" - addons.add(Ignore()) - assertThat(addons::commands).size().isEqualTo(3) - - assertThat(addons.names.ops, "names.ops").containsExactly("cycle") - - assertThat(addons.names.commands, "names.command").containsExactly( - "joke", - "rock", - "paper", - "scissors", - "ignore" - ) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt deleted file mode 100644 index 75a1cf9..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCi.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * DisableOnCi.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import org.junit.jupiter.api.extension.ExtendWith - -/** - * Disables tests on CI annotation. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @since 1.0 - */ -@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.RUNTIME) -@ExtendWith(DisableOnCiCondition::class) -annotation class DisableOnCi diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt b/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt deleted file mode 100644 index d887b55..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/DisableOnCiCondition.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * DisableOnCiCondition.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import org.junit.jupiter.api.extension.ConditionEvaluationResult -import org.junit.jupiter.api.extension.ExecutionCondition -import org.junit.jupiter.api.extension.ExtensionContext - -/** - * Disables tests on CI condition. - * - * @author [Erik C. Thauvin](https://erik.thauvin.net/) - * @since 1.0 - */ -class DisableOnCiCondition : ExecutionCondition { - override fun evaluateExecutionCondition(context: ExtensionContext): ConditionEvaluationResult { - return if (System.getenv("CI") != null) { - ConditionEvaluationResult.disabled("Test disabled on CI") - } else { - ConditionEvaluationResult.enabled("Test enabled") - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt b/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt deleted file mode 100644 index 3a4adb0..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/ExceptionSanitizer.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ExceptionSanitizer.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.modules.ModuleException - -object ExceptionSanitizer { - /** - * Returns a sanitized exception to avoid displaying api keys, etc. in CI logs. - */ - fun ModuleException.sanitize(vararg sanitize: String): ModuleException { - val search = sanitize.filter { it.isNotBlank() }.toTypedArray() - if (search.isNotEmpty()) { - val obfuscate = search.map { it.obfuscate() }.toTypedArray() - with(this) { - if (!cause?.message.isNullOrBlank()) { - return ModuleException( - debugMessage, - cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), - this - ) - } else if (!message.isNullOrBlank()) { - return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) - } - } - } - return this - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt deleted file mode 100644 index 0c3d1c6..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/FeedReaderTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * FeedReaderTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.io.FeedException -import net.thauvin.erik.mobibot.FeedReader.Companion.readFeed -import net.thauvin.erik.mobibot.msg.Message -import java.io.IOException -import java.net.MalformedURLException -import java.net.UnknownHostException -import kotlin.test.Test - -class FeedReaderTest { - @Test - fun readFeedTest() { - var messages = readFeed("https://feeds.thauvin.net/ethauvin") - assertThat(messages, "messages").all { - size().isEqualTo(10) - index(1).prop(Message::msg).contains("erik.thauvin.net") - } - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=0") - assertThat(messages, "messages").index(0).prop(Message::msg).contains("nothing") - - messages = readFeed("https://lorem-rss.herokuapp.com/feed?length=84", 42) - assertThat(messages, "messages").size().isEqualTo(84) - messages.forEachIndexed { i, m -> - if (i % 2 == 0) { - assertThat(m, "messages($i)").prop(Message::msg).startsWith("Lorem ipsum") - } else { - assertThat(m, "messages($i)").prop(Message::msg).contains("http://example.com/test/") - } - } - - assertFailure { readFeed("blah") }.isInstanceOf(MalformedURLException::class.java) - - assertFailure { readFeed("https://www.example.com") }.isInstanceOf(FeedException::class.java) - - assertFailure { readFeed("https://www.thauvin.net/foo") }.isInstanceOf(IOException::class.java) - - assertFailure { readFeed("https://www.examplesfoo.com/") }.isInstanceOf(UnknownHostException::class.java) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt b/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt deleted file mode 100644 index 646a0ea..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/LocalProperties.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * LocalProperties.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import java.io.IOException -import java.net.InetAddress -import java.net.UnknownHostException -import java.nio.file.Files -import java.nio.file.Paths -import java.util.* - -/** - * Access to `local.properties`. - */ -open class LocalProperties { - init { - val localPath = Paths.get("local.properties") - if (Files.exists(localPath)) { - try { - Files.newInputStream(localPath).use { stream -> localProps.load(stream) } - } catch (ignore: IOException) { - // Do nothing - } - } - } - - companion object { - private val localProps = Properties() - - fun getHostName(): String { - val ciName = System.getenv("CI_NAME") - return ciName ?: try { - InetAddress.getLocalHost().hostName - } catch (ignore: UnknownHostException) { - "Unknown Host" - } - } - - fun getProperty(key: String): String { - return if (localProps.containsKey(key)) { - localProps.getProperty(key) - } else { - val env = System.getenv(keyToEnv(key)) - env?.let { - localProps.setProperty(key, env) - } - env - } - } - - private fun keyToEnv(key: String): String { - return key.replace('-', '_').uppercase() - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt deleted file mode 100644 index dafb862..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/PinboardTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * PinboardTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.entries.EntryLink -import java.net.URL -import kotlin.test.Test -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -class PinboardTest : LocalProperties() { - private val pinboard = Pinboard() - - @Test - fun testPinboard() { - val apiToken = getProperty("pinboard-api-token") - val url = "https://www.example.com/${(1000..5000).random()}" - val ircServer = "irc.test.com" - val entry = EntryLink(url, "Test Example", "ErikT", "", "#mobitopia", listOf("test")) - - pinboard.setApiToken(apiToken) - - pinboard.addPin(ircServer, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title, entry.nick, entry.channel), "addPin") - - entry.link = "https://www.example.com/${(5001..9999).random()}" - pinboard.updatePin(ircServer, url, entry) - assertTrue(validatePin(apiToken, url = entry.link, ircServer), "updatePin") - - entry.title = "Foo Title" - pinboard.updatePin(ircServer, entry.link, entry) - assertTrue(validatePin(apiToken, url = entry.link, entry.title), "updatePin(${entry.title}") - - pinboard.deletePin(entry) - assertFalse(validatePin(apiToken, url = entry.link), "deletePin") - } - - private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { - val response = - URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body - - matches.forEach { - if (!response.contains(it)) { - return false - } - } - - return response.contains(url) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt deleted file mode 100644 index bd05f70..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/UtilsTest.kt +++ /dev/null @@ -1,275 +0,0 @@ -/* - * UtilsTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.length -import net.thauvin.erik.mobibot.Utils.appendIfMissing -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.Utils.capitalise -import net.thauvin.erik.mobibot.Utils.capitalizeWords -import net.thauvin.erik.mobibot.Utils.colorize -import net.thauvin.erik.mobibot.Utils.cyan -import net.thauvin.erik.mobibot.Utils.encodeUrl -import net.thauvin.erik.mobibot.Utils.getIntProperty -import net.thauvin.erik.mobibot.Utils.green -import net.thauvin.erik.mobibot.Utils.helpCmdSyntax -import net.thauvin.erik.mobibot.Utils.helpFormat -import net.thauvin.erik.mobibot.Utils.lastOrEmpty -import net.thauvin.erik.mobibot.Utils.obfuscate -import net.thauvin.erik.mobibot.Utils.plural -import net.thauvin.erik.mobibot.Utils.reader -import net.thauvin.erik.mobibot.Utils.red -import net.thauvin.erik.mobibot.Utils.replaceEach -import net.thauvin.erik.mobibot.Utils.reverseColor -import net.thauvin.erik.mobibot.Utils.toIntOrDefault -import net.thauvin.erik.mobibot.Utils.toIsoLocalDate -import net.thauvin.erik.mobibot.Utils.toUtcDateTime -import net.thauvin.erik.mobibot.Utils.today -import net.thauvin.erik.mobibot.Utils.underline -import net.thauvin.erik.mobibot.Utils.unescapeXml -import net.thauvin.erik.mobibot.msg.Message.Companion.DEFAULT_COLOR -import org.junit.jupiter.api.BeforeEach -import org.pircbotx.Colors -import java.io.File -import java.io.IOException -import java.net.URL -import java.time.LocalDateTime -import java.util.* -import kotlin.test.Test - -class UtilsTest { - private val ascii = - " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" - private val cal = Calendar.getInstance() - private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) - private val test = "This is a test." - - @BeforeEach - fun setUp() { - cal[1952, Calendar.FEBRUARY, 17, 12, 30] = 0 - } - - @Test - fun testAppendIfMissing() { - val dir = "dir" - val sep = '/' - val url = "https://erik.thauvin.net" - assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") - .isEqualTo(dir + File.separatorChar) - assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") - assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") - } - - @Test - fun testBold() { - assertThat(1.bold(), "bold(1)").isEqualTo(Colors.BOLD + "1" + Colors.BOLD) - assertThat(2L.bold(), "bold(2L)").isEqualTo(Colors.BOLD + "2" + Colors.BOLD) - assertThat(ascii.bold(), "ascii.bold()").isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat("test".bold(), "test.bold()").isEqualTo(Colors.BOLD + "test" + Colors.BOLD) - } - - - @Test - fun testCapitalise() { - assertThat("test".capitalise(), "capitalize(test)").isEqualTo("Test") - assertThat("Test".capitalise(), "capitalize(Test)").isEqualTo("Test") - assertThat(test.capitalise(), "capitalize($test)").isEqualTo(test) - assertThat("".capitalise(), "capitalize()").isEqualTo("") - } - - @Test - fun textCapitaliseWords() { - assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") - assertThat("Already Capitalized".capitalizeWords(), "already capitalized") - .isEqualTo("Already Capitalized") - assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") - } - - @Test - fun testColorize() { - assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( - Colors.REVERSE + ascii + Colors.REVERSE - ) - assertThat(ascii.colorize(Colors.RED), "red.colorize()") - .isEqualTo(Colors.RED + ascii + Colors.NORMAL) - assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") - .isEqualTo(Colors.BOLD + ascii + Colors.BOLD) - assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") - assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") - assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) - assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") - .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) - } - - @Test - fun testCyan() { - assertThat(ascii.cyan()).isEqualTo(Colors.CYAN + ascii + Colors.NORMAL) - } - - @Test - fun testEncodeUrl() { - assertThat("Hello Günter".encodeUrl()).isEqualTo("Hello%20G%C3%BCnter") - } - - @Test - fun testGetIntProperty() { - val p = Properties() - p["one"] = "1" - p["two"] = "two" - assertThat(p.getIntProperty("one", 9), "getIntProperty(one)").isEqualTo(1) - assertThat(p.getIntProperty("two", 2), "getIntProperty(two)").isEqualTo(2) - assertThat(p.getIntProperty("foo", 3), "getIntProperty(foo)").isEqualTo(3) - } - - @Test - fun testGreen() { - assertThat(ascii.green()).isEqualTo(Colors.DARK_GREEN + ascii + Colors.NORMAL) - } - - @Test - fun testHelpCmdSyntax() { - val bot = "mobibot" - assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") - .isEqualTo("$bot: $test $bot $test") - assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") - .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") - } - - @Test - fun testHelpFormat() { - assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") - .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") - assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") - .isEqualTo(test.prependIndent()) - assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") - .isEqualTo(test.colorize(Colors.BOLD).prependIndent()) - - } - - @Test - fun testIsoLocalDate() { - assertThat(cal.time.toIsoLocalDate(), "isoLocalDate(date)").isEqualTo("1952-02-17") - assertThat(localDateTime.toIsoLocalDate(), "isoLocalDate(localDate)").isEqualTo("1952-02-17") - } - - @Test - fun testLastOrEmpty() { - val two = listOf("1", "2") - assertThat(two.lastOrEmpty(), "lastOrEmpty(1,2)").isEqualTo("2") - val one = listOf("1") - assertThat(one.lastOrEmpty(), "lastOrEmpty(1)").isEqualTo("") - } - - @Test - fun testObfuscate() { - assertThat(ascii.obfuscate(), "obfuscate()").all { - length().isEqualTo(ascii.length) - isEqualTo(("x".repeat(ascii.length))) - } - assertThat(" ".obfuscate(), "obfuscate(blank)").isEqualTo(" ") - } - - @Test - fun testPlural() { - val week = "week" - val weeks = "weeks" - - for (i in -1..3) { - assertThat(week.plural(i.toLong()), "plural($i)").isEqualTo(if (i > 1) weeks else week) - } - } - - @Test - fun testReplaceEach() { - val search = arrayOf("one", "two", "three") - val replace = arrayOf("1", "2", "3") - assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") - .isEqualTo(replace.joinToString(",")) - - assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) - - assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") - .isEqualTo(test.replace("t", "").replace("e", "E")) - - assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") - .isEqualTo(test) - } - - @Test - fun testRed() { - assertThat(ascii.red()).isEqualTo(ascii.colorize(Colors.RED)) - } - - @Test - fun testReverseColor() { - assertThat(ascii.reverseColor()).isEqualTo(Colors.REVERSE + ascii + Colors.REVERSE) - } - - @Test - fun testToday() { - assertThat(today()).isEqualTo(LocalDateTime.now().toIsoLocalDate()) - } - - @Test - fun testToIntOrDefault() { - assertThat("10".toIntOrDefault(1), "toIntOrDefault(10, 1)").isEqualTo(10) - assertThat("a".toIntOrDefault(2), "toIntOrDefault(a, 2)").isEqualTo(2) - } - - @Test - fun testUnderline() { - assertThat(ascii.underline()).isEqualTo(ascii.colorize(Colors.UNDERLINE)) - } - - @Test - fun testUnescapeXml() { - assertThat("<a name="test & ''">".unescapeXml()).isEqualTo( - "<a name=\"test & ''\">" - ) - } - - @Test - @Throws(IOException::class) - fun testUrlReader() { - val reader = URL("https://postman-echo.com/status/200").reader() - assertThat(reader.body).isEqualTo("{\n \"status\": 200\n}") - assertThat(reader.responseCode).isEqualTo(200) - } - - @Test - fun testUtcDateTime() { - assertThat(cal.time.toUtcDateTime(), "utcDateTime(date)").isEqualTo("1952-02-17 12:30") - assertThat(localDateTime.toUtcDateTime(), "utcDateTime(localDate)").isEqualTo("1952-02-17 12:30") - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt deleted file mode 100644 index f332005..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/InfoTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * InfoTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.commands.Info.Companion.toUptime -import kotlin.test.Test - -class InfoTest { - @Test - fun testToUptime() { - assertThat( - 547800300076L.toUptime(), - "upTime(full)" - ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") - assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") - assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") - assertThat( - 1320300000L.toUptime(), - "upTime(weeks days hours minutes)" - ).isEqualTo("2 weeks 1 day 6 hours 45 minutes") - assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") - assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") - assertThat(59000L.toUptime(), "upTime(59 seconds)").isEqualTo("59 seconds") - assertThat(0L.toUptime(), "upTime(0 second)").isEqualTo("0 second") - - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt deleted file mode 100644 index ef6f461..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/RecapTest.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * RecapTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import assertk.assertions.prop -import assertk.assertions.size -import kotlin.test.Test - -class RecapTest { - @Test - fun storeRecapTest() { - for (i in 1..20) { - Recap.storeRecap("sender$i", "test $i", false) - } - assertThat(Recap.recaps, "Recap.recaps").all { - size().isEqualTo(Recap.MAX_RECAPS) - prop(MutableList<String>::first) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) - prop(MutableList<String>::last) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) - } - - Recap.storeRecap("sender", "test action", true) - assertThat(Recap.recaps.last()) - .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt deleted file mode 100644 index 676c5b6..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/LinksManagerTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * LinksManagerTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isEqualTo -import assertk.assertions.isTrue -import assertk.assertions.size -import net.thauvin.erik.mobibot.Constants -import kotlin.test.Test - -class LinksManagerTest { - private val linksManager = LinksManager() - - @Test - fun fetchTitle() { - assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") - assertThat( - linksManager.fetchTitle("https://www.google.com/foo"), - "fetchTitle(Foo)" - ).isEqualTo(Constants.NO_TITLE) - } - - @Test - fun testMatches() { - assertThat(linksManager.matches("https://www.example.com/"), "matches(url)").isTrue() - assertThat(linksManager.matches("HTTP://erik.thauvin.net/blog/ Erik's Weblog"), "matches(HTTP)").isTrue() - } - - @Test - fun matchTagKeywordsTest() { - linksManager.setProperty(LinksManager.KEYWORDS_PROP, "key1 key2,key3") - val tags = mutableListOf<String>() - - linksManager.matchTagKeywords("Test title with key2", tags) - assertThat(tags, "tags").contains("key2") - tags.clear() - - linksManager.matchTagKeywords("Test key3 title with key1", tags) - assertThat(tags, "tags(key1, key3)").all { - contains("key1") - contains("key3") - size().isEqualTo(2) - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt deleted file mode 100644 index abf8224..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/links/ViewTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ViewTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.links - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.prop -import net.thauvin.erik.mobibot.entries.EntryLink -import kotlin.test.Test - -class ViewTest { - @Test - fun testParseArgs() { - val view = View() - - for (i in 1..10) { - LinksManager.entries.links.add( - EntryLink( - "https://www.example.com/$i", - "Example $i", - "nick$i", - "login$i", - "#channel", - emptyList() - ) - ) - } - - assertThat(view.parseArgs("1"), "parseArgs(1)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("") - } - - assertThat(view.parseArgs("2 foo"), "parseArgs(2, foo)").all { - prop(Pair<Int, String>::first).isEqualTo(1) - prop(Pair<Int, String>::second).isEqualTo("foo") - } - - assertThat(view.parseArgs("3 FOO"), "parseArgs(3, FOO)").all { - prop(Pair<Int, String>::first).isEqualTo(2) - prop(Pair<Int, String>::second).isEqualTo("foo") - } - - assertThat(view.parseArgs(" 4 foo bar "), "parseArgs( 4 foo bar )").all { - prop(Pair<Int, String>::first).isEqualTo(3) - prop(Pair<Int, String>::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("foo bar"), "parseArgs(foo bar)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("foo bar") - } - - assertThat(view.parseArgs("${Int.MAX_VALUE}1"), "parseArgs(overflow)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("${Int.MAX_VALUE}1") - } - - assertThat(view.parseArgs("1a"), "parseArgs(1a)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("1a") - } - - assertThat(view.parseArgs("20"), "parseArgs(20)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("") - } - - assertThat(view.parseArgs(""), "parseArgs()").all { - prop(Pair<Int, String>::first).isEqualTo(LinksManager.entries.links.size - View.MAX_ENTRIES) - prop(Pair<Int, String>::second).isEqualTo("") - } - - LinksManager.entries.links.clear() - - assertThat(view.parseArgs("4"), "parseArgs(4)").all { - prop(Pair<Int, String>::first).isEqualTo(0) - prop(Pair<Int, String>::second).isEqualTo("") - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt deleted file mode 100644 index 7b946dc..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/seen/SeenTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SeenTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.seen - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.junit.AfterClass -import org.junit.BeforeClass -import org.junit.jupiter.api.Order -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize -import kotlin.test.Test - -class SeenTest { - @Test - @Order(1) - fun loadTest() { - seen.clear() - assertThat(seen::seenNicks).isEmpty() - seen.load() - assertThat(seen::seenNicks).key(NICK).isNotNull() - } - - @Test - @Order(2) - fun addTest() { - val last = seen.seenNicks[NICK]?.lastSeen - seen.add(NICK.lowercase()) - assertThat(seen).all { - prop(Seen::seenNicks).size().isEqualTo(1) - prop(Seen::seenNicks).key(NICK).isNotNull().prop(SeenNick::lastSeen).isNotEqualTo(last) - prop(Seen::seenNicks).key(NICK).isNotNull().prop(SeenNick::nick).isNotNull().isEqualTo(NICK.lowercase()) - } - } - - @Test - @Order(3) - fun clearTest() { - seen.clear() - seen.save() - seen.load() - assertThat(seen::seenNicks).size().isEqualTo(0) - } - - companion object { - private val tmpFile = kotlin.io.path.createTempFile(suffix = ".ser") - private val seen = Seen(tmpFile.toAbsolutePath().toString()) - private const val NICK = "ErikT" - - @JvmStatic - @BeforeClass - fun beforeClass() { - seen.add(NICK) - assertThat(tmpFile.fileSize(), "tmpFile.size").isGreaterThan(0) - } - - @JvmStatic - @AfterClass - fun afterClass() { - tmpFile.deleteIfExists() - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt deleted file mode 100644 index 443c1f9..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessageTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * TellMessageTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import java.time.Duration -import java.time.LocalDateTime -import java.time.temporal.Temporal -import kotlin.test.Test - -class TellMessageTest { - private fun isValidDate(date: Temporal): Boolean { - return Duration.between(date, LocalDateTime.now()).toMinutes() < 1 - } - - @Test - fun testTellMessage() { - val message = "Test message." - val recipient = "recipient" - val sender = "sender" - val tellMessage = TellMessage(sender, recipient, message) - assertThat(tellMessage).all { - prop(TellMessage::sender).isEqualTo(sender) - prop(TellMessage::recipient).isEqualTo(recipient) - prop(TellMessage::message).isEqualTo(message) - } - assertThat(isValidDate(tellMessage.queued), "isValidDate()").isTrue() - assertThat(tellMessage.isMatch(sender), "isMatch(sender)").isTrue() - assertThat(tellMessage.isMatch(recipient), "isMatch(recipient)").isTrue() - assertThat(tellMessage.isMatch("foo"), "isMatch(foo)").isFalse() - tellMessage.isReceived = false - assertThat(tellMessage.receptionDate, "receptionDate").isEqualTo(LocalDateTime.MIN) - tellMessage.isReceived = true - assertThat(isValidDate(tellMessage.receptionDate), "isValidDate(creationDate)").isTrue() - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt deleted file mode 100644 index 6d3bb6b..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/commands/tell/TellMessagesMgrTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * TellMessagesMgrTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.commands.tell - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import org.junit.AfterClass -import java.time.LocalDateTime -import kotlin.io.path.createTempFile -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize -import kotlin.test.Test - -class TellMessagesMgrTest { - private val maxDays = 10L - private val testMessages = mutableListOf<TellMessage>().apply { - for (i in 0..5) { - this.add(i, TellMessage("sender$i", "recipient$i", "message $i")) - } - } - - init { - TellManager.save(testFile.toAbsolutePath().toString(), testMessages) - assertThat(testFile.fileSize()).isGreaterThan(0) - } - - @Test - fun cleanTest() { - testMessages.add(TellMessage("sender", "recipient", "message").apply { - queued = LocalDateTime.now().minusDays(maxDays) - }) - val size = testMessages.size - assertThat(TellManager.clean(testMessages, maxDays + 2), "clean(maxDays=${maxDays + 2})").isFalse() - assertThat(TellManager.clean(testMessages, maxDays), "clean(maxDays=$maxDays)").isTrue() - assertThat(testMessages, "testMessages").size().isEqualTo(size - 1) - } - - @Test - fun loadTest() { - val messages = TellManager.load(testFile.toAbsolutePath().toString()) - for (i in messages.indices) { - assertThat(messages).index(i).all { - prop(TellMessage::sender).isEqualTo(testMessages[i].sender) - prop(TellMessage::recipient).isEqualTo(testMessages[i].recipient) - prop(TellMessage::message).isEqualTo(testMessages[i].message) - } - } - } - - companion object { - private val testFile = createTempFile(suffix = ".ser") - - @JvmStatic - @AfterClass - fun afterClass() { - testFile.deleteIfExists() - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt deleted file mode 100644 index f67a057..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntriesUtilsTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * EntriesUtilsTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.Constants -import net.thauvin.erik.mobibot.entries.EntriesUtils.printComment -import net.thauvin.erik.mobibot.entries.EntriesUtils.printLink -import net.thauvin.erik.mobibot.entries.EntriesUtils.printTags -import net.thauvin.erik.mobibot.entries.EntriesUtils.toLinkLabel -import kotlin.test.Test - -class EntriesUtilsTest { - private val comment = EntryComment("comment", "nick") - private val links = buildList { - for (i in 0..5) { - add( - EntryLink( - "https://www.mobitopia.org/$i", - "Mobitopia$i", - "Skynx$i", - "JimH$i", - "#mobitopia$i", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - ) - } - } - - @Test - fun printCommentTest() { - assertThat(printComment(0, 0, comment)).isEqualTo("${Constants.LINK_CMD}1.1: [nick] comment") - } - - @Test - fun printLinkTest() { - for (i in links.indices) { - assertThat( - printLink(i - 1, links[i]), "link $i" - ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") - } - - assertThat(links.first().addComment(comment), "addComment()").isEqualTo(0) - assertThat(printLink(0, links.first(), isView = true), "printLink(isView=true)").contains("[+1]") - } - - @Test - fun printTagsTest() { - for (i in links.indices) { - assertThat( - printTags(i - 1, links[i]), "tag $i" - ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") - } - } - - @Test - fun toLinkLabelTest() { - assertThat(1.toLinkLabel()).isEqualTo("${Constants.LINK_CMD}2") - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt deleted file mode 100644 index 3479108..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/EntryLinkTest.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * EntryLinkTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import com.rometools.rome.feed.synd.SyndCategory -import com.rometools.rome.feed.synd.SyndCategoryImpl -import java.security.SecureRandom -import java.util.* -import kotlin.test.Test - -class EntryLinkTest { - private val entryLink = EntryLink( - "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", - listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") - ) - - @Test - fun testAddDeleteComment() { - var i = 0 - while (i < 5) { - entryLink.addComment("c$i", "u$i") - i++ - } - assertThat(entryLink.comments, "comments").size().isEqualTo(i) - i = 0 - for (comment in entryLink.comments) { - assertThat(comment).all { - prop(EntryComment::comment).isEqualTo("c$i") - prop(EntryComment::nick).isEqualTo("u$i") - } - i++ - } - - val r = SecureRandom() - while (entryLink.comments.size > 0) { - entryLink.deleteComment(r.nextInt(entryLink.comments.size)) - } - assertThat(entryLink.comments, "hasComments()").isEmpty() - entryLink.addComment("nothing", "nobody") - entryLink.setComment(0, "something", "somebody") - val comment = entryLink.getComment(0) - assertThat(comment, "comment[first]").all { - prop(EntryComment::nick).isEqualTo("somebody") - prop(EntryComment::comment).isEqualTo("something") - } - assertThat(entryLink.deleteComment(comment), "deleteComment").isTrue() - assertThat(entryLink.deleteComment(comment), "comment is already deleted").isFalse() - } - - @Test - fun testConstructor() { - val tags = listOf(SyndCategoryImpl().apply { name = "tag1" }, SyndCategoryImpl().apply { name = "tag2" }) - val link = EntryLink("link", "title", "nick", "channel", Date(), tags) - assertThat(link, "link").all { - prop(EntryLink::tags).size().isEqualTo(tags.size) - prop(EntryLink::tags).index(0).prop(SyndCategory::getName).isEqualTo("tag1") - } - } - - @Test - fun testMatches() { - assertThat(entryLink.matches("mobitopia"), "matches(mobitopia)").isTrue() - assertThat(entryLink.matches("skynx"), "match(nick)").isTrue() - assertThat(entryLink.matches("www.mobitopia.org"), "matches(url)").isTrue() - assertThat(entryLink.matches("foo"), "matches(foo)").isFalse() - assertThat(entryLink.matches("<empty>"), "matches(empty)").isFalse() - assertThat(entryLink.matches(null), "matches(null)").isFalse() - } - - - @Test - fun testTags() { - val tags: List<SyndCategory> = entryLink.tags - for ((i, tag) in tags.withIndex()) { - assertThat(tag.name, "tag.name($i)").isEqualTo("tag${i + 1}") - } - assertThat(entryLink::tags).size().isEqualTo(5) - entryLink.setTags("-tag5, tag4") - entryLink.setTags("+mobitopia") - entryLink.setTags("-mobitopia") - assertThat( - entryLink.formatTags(","), - "formatTags(',')" - ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") - entryLink.setTags("-tag4 tag5") - assertThat( - entryLink.formatTags(" ", ","), "formatTag(' ',',')" - ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") - val size = entryLink.tags.size - entryLink.setTags("") - assertThat(entryLink.tags, "setTags('')").size().isEqualTo(size) - entryLink.setTags(" ") - assertThat(entryLink.tags, "setTags(' ')").size().isEqualTo(size) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt deleted file mode 100644 index 5803092..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/entries/FeedMgrTest.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * FeedMgrTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.entries - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.Utils.today -import java.nio.file.Paths -import java.util.* -import kotlin.io.path.deleteIfExists -import kotlin.io.path.fileSize -import kotlin.io.path.name -import kotlin.test.Test - -class FeedMgrTest { - private val entries = Entries() - private val channel = "mobibot" - - init { - entries.logsDir = "src/test/resources/" - entries.ircServer = "irc.example.com" - entries.channel = channel - entries.backlogs = "https://www.mobitopia.org/mobibot/logs" - } - - @Test - fun testFeedMgr() { - // Load the feed - assertThat(FeedsManager.loadFeed(entries), "loadFeed()").isEqualTo("2021-10-31") - - assertThat(entries.links, "entries.links").size().isEqualTo(2) - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink, "entryLink[${i + 1}]").all { - prop(EntryLink::title).isEqualTo("Example ${i + 1}") - prop(EntryLink::link).isEqualTo("https://www.example.com/${i + 1}") - prop(EntryLink::channel).isEqualTo(channel) - } - entryLink.tags.forEachIndexed { y, tag -> - assertThat(tag.name, "tag${i + 1}-${y + 1}").isEqualTo("tag${i + 1}-${y + 1}") - } - } - - with(entries.links.first()) { - assertThat(nick, "nick[first]").isEqualTo("ErikT") - assertThat(date, "date[first]").isEqualTo(Date(1635638400000L)) - assertThat(comments.first(), "comments[first]").all { - prop(EntryComment::comment).endsWith("comment 1.") - prop(EntryComment::nick).isEqualTo("ErikT") - } - assertThat(comments.last(), "comments[last]").all { - prop(EntryComment::comment).endsWith("comment 2.") - prop(EntryComment::nick).isEqualTo("Skynx") - } - } - - assertThat(entries.links, "links").index(1).all { - prop(EntryLink::nick).isEqualTo("Skynx") - prop(EntryLink::date).isEqualTo(Date(1635638460000L)) - } - - val currentFile = Paths.get("${entries.logsDir}test.xml") - val backlogFile = Paths.get("${entries.logsDir}${today()}.xml") - - // Save the feed - FeedsManager.saveFeed(entries, currentFile.name) - - assertThat(currentFile, "currentFile").exists() - assertThat(backlogFile, "backlogFile").exists() - - assertThat(currentFile.fileSize(), "currentFile == backlogFile").isEqualTo(backlogFile.fileSize()) - - // Load the test feed - entries.links.clear() - FeedsManager.loadFeed(entries, currentFile.name) - - entries.links.forEachIndexed { i, entryLink -> - assertThat(entryLink.title, "entryLink.title[${i + 1}]").isEqualTo("Example ${i + 1}") - } - - assertThat(currentFile.deleteIfExists(), "currentFile.deleteIfExists()").isTrue() - assertThat(backlogFile.deleteIfExists(), "backlogFile.deleteIfExists()").isTrue() - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt deleted file mode 100644 index 140b8a1..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CalcTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * CalcTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isInstanceOf -import net.objecthunter.exp4j.tokenizer.UnknownFunctionOrVariableException -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.modules.Calc.Companion.calculate -import kotlin.test.Test - -class CalcTest { - @Test - fun testCalculate() { - assertThat(calculate("1 + 1"), "calculate(1+1)").isEqualTo("1+1 = ${2.bold()}") - assertThat(calculate("1 -3"), "calculate(1-3)").isEqualTo("1-3 = ${(-2).bold()}") - assertThat(calculate("pi+π+e+φ"), "calculate(pi+π+e+φ)").isEqualTo("pi+π+e+φ = ${"10.62".bold()}") - assertFailure { calculate("one + one") }.isInstanceOf(UnknownFunctionOrVariableException::class.java) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt deleted file mode 100644 index ee3e534..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ChatGpt2Test.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ChatGpt2Test.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasNoCause -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.DisableOnCi -import net.thauvin.erik.mobibot.LocalProperties -import kotlin.test.Test - -class ChatGpt2Test : LocalProperties() { - @Test - fun testApiKey() { - assertFailure { ChatGpt2.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() - } - - @Test - @DisableOnCi - fun testChat() { - val apiKey = getProperty(ChatGpt2.API_KEY_PROP) - assertThat( - ChatGpt2.chat("how do I make an HTTP request in Javascript?", apiKey, 200) - ).contains("XMLHttpRequest") - - assertFailure { ChatGpt2.chat("1 liter to gallon", apiKey, -1) } - .isInstanceOf(ModuleException::class.java) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt deleted file mode 100644 index 94a40d9..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CryptoPricesTest.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * CryptoPricesTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.isGreaterThan -import assertk.assertions.prop -import net.thauvin.erik.crypto.CryptoPrice -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.currentPrice -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.getCurrencyName -import net.thauvin.erik.mobibot.modules.CryptoPrices.Companion.loadCurrencies -import org.junit.jupiter.api.BeforeAll -import java.util.logging.ConsoleHandler -import java.util.logging.Level -import kotlin.test.Test - -class CryptoPricesTest { - init { - loadCurrencies() - } - - @Test - @Throws(ModuleException::class) - fun testMarketPrice() { - var price = currentPrice(listOf("BTC")) - assertThat(price, "currentPrice(BTC)").all { - prop(CryptoPrice::base).isEqualTo("BTC") - prop(CryptoPrice::currency).isEqualTo("USD") - prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) - } - - price = currentPrice(listOf("ETH", "EUR")) - assertThat(price, "currentPrice(ETH, EUR)").all { - prop(CryptoPrice::base).isEqualTo("ETH") - prop(CryptoPrice::currency).isEqualTo("EUR") - prop(CryptoPrice::amount).transform { it.signum() }.isGreaterThan(0) - } - } - - @Test - fun testGetCurrencyName() { - assertThat(getCurrencyName("USD"), "USD").isEqualTo("United States Dollar") - assertThat(getCurrencyName("EUR"), "EUR").isEqualTo("Euro") - } - - companion object { - @JvmStatic - @BeforeAll - fun beforeAll() { - with(CryptoPrice.logger) { - addHandler(ConsoleHandler().apply { level = Level.FINE }) - level = Level.FINE - useParentHandlers = false - } - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt deleted file mode 100644 index c1c0efc..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/CurrencyConverterTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * CurrencyConverterTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isInstanceOf -import assertk.assertions.matches -import assertk.assertions.prop -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.convertCurrency -import net.thauvin.erik.mobibot.modules.CurrencyConverter.Companion.loadSymbols -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import kotlin.test.Test - -class CurrencyConverterTest : LocalProperties() { - init { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - loadSymbols(apiKey) - } - - @Test - fun testConvertCurrency() { - val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) - assertThat( - convertCurrency(apiKey, "100 USD to EUR").msg, - "convertCurrency(100 USD to EUR)" - ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) - assertThat( - convertCurrency(apiKey, "1 USD to GBP").msg, - "convertCurrency(1 USD to BGP)" - ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) - assertThat( - convertCurrency(apiKey, "100,000.00 CAD to USD").msg, - "convertCurrency(100,000.00 GBP to USD)" - ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) - assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all { - prop(Message::msg).contains("You're kidding, right?") - isInstanceOf(PublicMessage::class.java) - } - assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all { - prop(Message::msg).contains("Invalid query.") - isInstanceOf(ErrorMessage::class.java) - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt deleted file mode 100644 index e34de7b..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/DiceTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * DiceTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - - -import assertk.assertThat -import assertk.assertions.isEqualTo -import assertk.assertions.matches -import kotlin.test.Test - -class DiceTest { - @Test - fun testRoll() { - assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") - assertThat(Dice.roll(2, 1), "roll(2d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") - assertThat(Dice.roll(5, 1), "roll(5d1)") - .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") - assertThat(Dice.roll(2, 6), "roll(2d6)") - .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) - assertThat(Dice.roll(3, 7), "roll(3d7)") - .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt deleted file mode 100644 index 269874a..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Gemini2Test.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Gemini2Test.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.DisableOnCi -import net.thauvin.erik.mobibot.LocalProperties -import kotlin.test.Test - -class Gemini2Test : LocalProperties() { - @Test - fun testApiKey() { - assertFailure { Gemini2.chat("1 gallon to liter", "", 0) } - .isInstanceOf(ModuleException::class.java) - .hasNoCause() - } - - @Test - @DisableOnCi - fun chatPrompt() { - val apiKey = getProperty(Gemini2.GEMINI_API_KEY) - val maxTokens = getProperty(Gemini2.MAX_TOKENS_PROP).toInt() - - assertThat( - Gemini2.chat("how do I make an HTTP request in Javascript?", apiKey, maxTokens) - ).isNotNull().contains("XMLHttpRequest") - - assertThat( - Gemini2.chat("how do I encode a URL in java?", apiKey, 60) - ).isNotNull().contains("URLEncoder") - - assertFailure { Gemini2.chat("1 liter to gallon", "foo", 40) } - .isInstanceOf(ModuleException::class.java) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt deleted file mode 100644 index f9b0832..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/GoogleSearchTest.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * GoogleSearchTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.DisableOnCi -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.GoogleSearch.Companion.searchGoogle -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -class GoogleSearchTest : LocalProperties() { - @Test - fun testAPIKeys() { - assertThat( - searchGoogle("", "apikey", "cssKey").first(), - "searchGoogle(empty)" - ).isInstanceOf(ErrorMessage::class.java) - - assertFailure { searchGoogle("test", "", "apiKey") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "") } - .isInstanceOf(ModuleException::class.java).hasNoCause() - - assertFailure { searchGoogle("test", "apiKey", "cssKey") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("API key not valid. Please pass a valid API key.") - } - - @Test - @DisableOnCi - @Throws(ModuleException::class) - fun testSearchGoogle() { - val apiKey = getProperty(GoogleSearch.API_KEY_PROP) - val cseKey = getProperty(GoogleSearch.CSE_KEY_PROP) - - try { - var query = "mobibot" - var messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").all { - isNotEmpty() - index(0).prop(Message::msg).contains(query, true) - } - - query = "adadflkjl" - messages = searchGoogle(query, apiKey, cseKey) - assertThat(messages, "searchGoogle($query)").index(0).all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo("No results found.") - } - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey, cseKey) - } else { - throw e - } - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt deleted file mode 100644 index cf6d03c..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/JokeTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * JokeTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.modules.Joke.Companion.randomJoke -import net.thauvin.erik.mobibot.msg.Message -import net.thauvin.erik.mobibot.msg.PublicMessage -import kotlin.test.Test - -class JokeTest { - @Test - @Throws(ModuleException::class) - fun testRandomJoke() { - val joke = randomJoke() - assertThat(joke, "randomJoke()").all { - size().isGreaterThan(0) - each { - it.isInstanceOf(PublicMessage::class.java) - it.prop(Message::msg).doesNotContain("\n") - } - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt deleted file mode 100644 index abb9235..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/LookupTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * LookupTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertThat -import assertk.assertions.any -import assertk.assertions.contains -import net.thauvin.erik.mobibot.modules.Lookup.Companion.nslookup -import net.thauvin.erik.mobibot.modules.Lookup.Companion.whois -import kotlin.test.Test - -class LookupTest { - @Test - @Throws(Exception::class) - fun testLookup() { - var result = nslookup("apple.com") - assertThat(result, "lookup(apple.com)").contains("17.253.144.10") - - result = nslookup("37.27.52.13") - assertThat(result, "lookup(37.27.52.13)").contains("nix4.thauvin.us") - } - - @Test - @Throws(Exception::class) - fun testWhois() { - val result = whois("17.178.96.59", Lookup.WHOIS_HOST) - assertThat(result, "whois(17.178.96.59").any { it.contains("Apple Inc.") } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt deleted file mode 100644 index a9e1d43..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/MastodonTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MastodonTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Mastodon.Companion.toot -import kotlin.test.Test - -class MastodonTest : LocalProperties() { - @Test - @Throws(ModuleException::class) - fun testToot() { - val msg = "Testing Mastodon API from ${getHostName()}" - assertThat( - toot( - getProperty(Mastodon.ACCESS_TOKEN_PROP), - getProperty(Mastodon.INSTANCE_PROP), - getProperty(Mastodon.HANDLE_PROP), - msg, - true - ) - ).contains(msg) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt deleted file mode 100644 index 6c3c54c..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/ModuleExceptionTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * ModuleExceptionTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource -import java.io.IOException -import kotlin.test.Test - -class ModuleExceptionTest { - companion object { - const val DEBUG_MESSAGE = "debugMessage" - const val MESSAGE = "message" - - @JvmStatic - fun dataProviders(): List<ModuleException> { - return listOf( - ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com")), - ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?")), - ModuleException(DEBUG_MESSAGE, MESSAGE) - ) - } - } - - @ParameterizedTest - @MethodSource("dataProviders") - fun testGetDebugMessage(e: ModuleException) { - assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE) - } - - @ParameterizedTest - @MethodSource("dataProviders") - fun testGetMessage(e: ModuleException) { - assertThat(e).hasMessage(MESSAGE) - } - - @Test - fun testSanitizeMessage() { - val apiKey = "1234567890" - var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) - assertThat( - e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" - ).isNotNull().all { - contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") - doesNotContain(apiKey, "me") - } - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, null) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException()) - assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE) - - e = ModuleException(DEBUG_MESSAGE, apiKey) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() - .doesNotContain(apiKey) - - val msg: String? = null - e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg)) - assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() - - e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey")) - assertThat( - e.sanitize(" ", apiKey, "foo").message, - "ModuleException(debugMessage, msg, IOException(foo is $apiKey))" - ).isNotNull().all { - doesNotContain(apiKey) - endsWith("xxx is xxxxxxxxxx") - } - assertThat(e.sanitize(), "exception should be unchanged").isEqualTo(e) - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt deleted file mode 100644 index f51e203..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/PingTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * PingTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.isNotEmpty -import net.thauvin.erik.mobibot.modules.Ping.Companion.randomPing -import kotlin.test.Test - -class PingTest { - @Test - fun testPingsArray() { - assertThat(Ping.PINGS, "Ping.PINGS").isNotEmpty() - } - - @Test - fun testRandomPing() { - for (i in 0..9) { - assertThat(Ping.PINGS, "Ping.PINGS[$i]").contains(randomPing()) - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt deleted file mode 100644 index 519037a..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/RockPaperScissorsTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * RockPaperScissorsTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertThat -import assertk.assertions.isEqualTo -import net.thauvin.erik.mobibot.modules.RockPaperScissors.Companion.winLoseOrDraw -import kotlin.test.Test - -class RockPaperScissorsTest { - @Test - fun testWinLoseOrDraw() { - assertThat(winLoseOrDraw("scissors", "paper"), "scissors vs. paper").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "rock"), "paper vs. rock").isEqualTo("win") - assertThat(winLoseOrDraw("rock", "scissors"), "rock vs. scissors").isEqualTo("win") - assertThat(winLoseOrDraw("paper", "scissors"), "paper vs. scissors").isEqualTo("lose") - assertThat(winLoseOrDraw("rock", "paper"), "rock vs. paper").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "rock"), "scissors vs. rock").isEqualTo("lose") - assertThat(winLoseOrDraw("scissors", "scissors"), "scissors vs. scissors").isEqualTo("draw") - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt deleted file mode 100644 index 955a267..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/StockQuoteTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * StockQuoteTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.StockQuote.Companion.getQuote -import net.thauvin.erik.mobibot.msg.ErrorMessage -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -class StockQuoteTest : LocalProperties() { - private fun buildMatch(label: String): String { - return "${label}:[ ]+[0-9.]+".prependIndent() - } - - @Test - @Throws(ModuleException::class) - fun testGetQuote() { - val apiKey = getProperty(StockQuote.API_KEY_PROP) - try { - var symbol = "apple inc" - val messages = getQuote(symbol, apiKey) - assertThat(messages, "response not empty").isNotEmpty() - assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) - assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) - assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) - .matches(buildMatch("Previous").toRegex()) - assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) - - symbol = "blahfoo" - assertThat(getQuote(symbol, apiKey).first(), "getQuote($symbol)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertThat(getQuote("", "apikey").first(), "getQuote(empty)").all { - isInstanceOf(ErrorMessage::class.java) - prop(Message::msg).isEqualTo(StockQuote.INVALID_SYMBOL) - } - assertFailure { getQuote("test", "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - } catch (e: ModuleException) { - // Avoid displaying api keys in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt deleted file mode 100644 index 5d04560..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/Weather2Test.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Weather2Test.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.all -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.* -import net.aksingh.owmjapis.api.APIException -import net.aksingh.owmjapis.core.OWM -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.Weather2.Companion.API_KEY_PROP -import net.thauvin.erik.mobibot.modules.Weather2.Companion.ftoC -import net.thauvin.erik.mobibot.modules.Weather2.Companion.getCountry -import net.thauvin.erik.mobibot.modules.Weather2.Companion.getWeather -import net.thauvin.erik.mobibot.modules.Weather2.Companion.mphToKmh -import net.thauvin.erik.mobibot.msg.Message -import kotlin.test.Test - -class Weather2Test : LocalProperties() { - @Test - fun testFtoC() { - val t = ftoC(32.0) - assertThat(t.second, "32 °F is 0 °C").isEqualTo(0) - } - - @Test - fun testGetCountry() { - assertThat(getCountry("foo"), "foo is not a valid country").isEqualTo(OWM.Country.UNITED_STATES) - assertThat(getCountry("fr"), "country should France").isEqualTo(OWM.Country.FRANCE) - - val country = OWM.Country.entries.toTypedArray() - repeat(3) { - val rand = country[(country.indices).random()] - assertThat(getCountry(rand.value), rand.name).isEqualTo(rand) - } - } - - @Test - fun testMphToKmh() { - val w = mphToKmh(0.62) - assertThat(w.second, "0.62 mph is 1 km/h").isEqualTo(1) - } - - @Test - @Throws(ModuleException::class) - fun testWeather() { - var query = "98204" - var messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("Everett, United States") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("98204%2CUS") - - query = "San Francisco" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("San Francisco") - contains("US") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("5391959") - - query = "London, GB" - messages = getWeather(query, getProperty(API_KEY_PROP)) - assertThat(messages, "getWeather($query)").index(0).prop(Message::msg).all { - contains("London, United Kingdom") - contains("GB") - } - assertThat(messages, "getWeather($query)").index(messages.size - 1).prop(Message::msg).endsWith("2643743") - - try { - query = "Foo, US" - getWeather(query, getProperty(API_KEY_PROP)) - } catch (e: ModuleException) { - assertThat(e.cause, "getWeather($query)").isNotNull().isInstanceOf(APIException::class.java) - } - - query = "test" - assertFailure { getWeather(query, "") }.isInstanceOf(ModuleException::class.java).hasNoCause() - assertFailure { getWeather(query, null) }.isInstanceOf(ModuleException::class.java).hasNoCause() - - messages = getWeather("", "apikey") - assertThat(messages, "getWeather(empty)").index(0).prop(Message::isError).isTrue() - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt deleted file mode 100644 index 099f3f9..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WolframAlphaTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * WolframAlphaTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertFailure -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.hasMessage -import assertk.assertions.isInstanceOf -import net.thauvin.erik.mobibot.DisableOnCi -import net.thauvin.erik.mobibot.ExceptionSanitizer.sanitize -import net.thauvin.erik.mobibot.LocalProperties -import net.thauvin.erik.mobibot.modules.WolframAlpha.Companion.queryWolfram -import kotlin.test.Test - -class WolframAlphaTest : LocalProperties() { - @Test - fun testAppId() { - assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } - .isInstanceOf(ModuleException::class.java) - .hasMessage("Error 1: Invalid appid") - - assertFailure { queryWolfram("1 gallon to liter", appId = "") } - .isInstanceOf(ModuleException::class.java) - } - - @Test - @DisableOnCi - @Throws(ModuleException::class) - fun queryWolframTest() { - val apiKey = getProperty(WolframAlpha.APPID_KEY_PROP) - try { - var query = "SFO to SEA" - assertThat(queryWolfram(query, appId = apiKey), "queryWolfram($query)").contains("miles") - - query = "SFO to LAX" - assertThat( - queryWolfram(query, WolframAlpha.METRIC, apiKey), - "queryWolfram($query)" - ).contains("kilometers") - } catch (e: ModuleException) { - // Avoid displaying api key in CI logs - if ("true" == System.getenv("CI")) { - throw e.sanitize(apiKey) - } else { - throw e - } - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt deleted file mode 100644 index 396efaf..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/modules/WordTimeTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * WordTimeTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.modules - -import assertk.assertThat -import assertk.assertions.endsWith -import assertk.assertions.matches -import assertk.assertions.startsWith -import net.thauvin.erik.mobibot.Utils.bold -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.BEATS_KEYWORD -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.COUNTRIES_MAP -import net.thauvin.erik.mobibot.modules.WorldTime.Companion.time -import org.pircbotx.Colors -import java.time.ZoneId -import kotlin.test.Test - -class WordTimeTest { - @Test - fun testTime() { - assertThat(time(), "time()").matches( - ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + - "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + - "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() - ) - assertThat(time(""), "time()").endsWith("Los Angeles".bold()) - assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) - assertThat(time("GB"), "time(GB)").endsWith("London".bold()) - assertThat(time("FR"), "time(FR)").endsWith("Paris".bold()) - assertThat(time("BLAH"), "time(BLAH)").startsWith("Unsupported") - assertThat(time("BEAT"), "time($BEATS_KEYWORD)").matches("[\\w ]+ .?@\\d{3}+.? .beats".toRegex()) - } - - @Test - fun testZones() { - COUNTRIES_MAP.filter { it.value != BEATS_KEYWORD }.forEach { - assertThat(ZoneId.of(it.value)) - } - } -} diff --git a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt b/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt deleted file mode 100644 index 6e85ed1..0000000 --- a/src/test/kotlin/net/thauvin/erik/mobibot/msg/MessageTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * MessageTest.kt - * - * Copyright 2004-2025 Erik C. Thauvin (erik@thauvin.net) - * - * 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.mobibot.msg - -import assertk.all -import assertk.assertThat -import assertk.assertions.isFalse -import assertk.assertions.isTrue -import assertk.assertions.prop -import kotlin.test.Test - -class MessageTest { - @Test - fun testConstructor() { - var msg = Message("foo") - - msg.isError = true - assertThat(msg.isNotice, "message is notice").isTrue() - - msg = Message("foo", isError = true) - assertThat(msg.isNotice, "message is notice too").isTrue() - } - - @Test - fun testErrorMessage() { - val msg = ErrorMessage("foo") - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testIsError() { - val msg = Message("foo") - msg.isError = true - assertThat(msg).all { - prop(Message::isError).isTrue() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - msg.isError = false - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testNoticeMessage() { - val msg = NoticeMessage("food") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isTrue() - prop(Message::isPrivate).isFalse() - } - } - - @Test - fun testPrivateMessage() { - val msg = PrivateMessage("foo") - assertThat(msg).all { - prop(Message::isPrivate).isTrue() - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - } - } - - @Test - fun testPublicMessage() { - val msg = PublicMessage("foo") - assertThat(msg).all { - prop(Message::isError).isFalse() - prop(Message::isNotice).isFalse() - prop(Message::isPrivate).isFalse() - } - } -} diff --git a/src/test/resources/current.xml b/src/test/resources/current.xml deleted file mode 100644 index 8552a9a..0000000 --- a/src/test/resources/current.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"> - <channel> - <title>#mobibot IRC Links - https://www.mobitopia.org/mobibot/logs - Links from irc.example.com on #mobibot - en - Sun, 31 Oct 2021 21:45:11 GMT - 2021-10-31T21:45:11Z - en - - Example 2 - https://www.example.com/2 - Posted by <b>Skynx</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> - tag2-1 - tag2-2 - Sun, 31 Oct 2021 21:45:11 GMT - https://www.foo.com - mobibot@irc.libera.chat (Skynx) - 2021-10-31T00:01:00Z - - - Example 1 - https://www.example.com/1 - Posted by <b>ErikT</b> on <a href="irc://irc.libera.chat/#mobibot"><b>#mobibot</b></a> - <br/><br/>ErikT: This is comment 1. <br/>Skynx: This is comment 2. - - tag1-1 - tag1-2 - Sun, 31 Oct 2021 21:43:15 GMT - https://www.example.com/ - mobibot@irc.libera.chat (ErikT) - 2021-10-31T00:00:00Z - - - diff --git a/website/index.html b/website/index.html deleted file mode 100644 index 370c3cf..0000000 --- a/website/index.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - mobibot - - - - - - - - -
-

mobibot

- -

The #mobitopia bot

- -

The latest version of mobibot is always available via - GitHub. -

- -

About mobibot

- -

mobibot is the - #mobitopia IRC channel bot written in Kotlin. -

- -

mobibot is making extensive use of various open source libraries, including:

- -

mobibot was written by - Erik C. Thauvin as a replacement for the channel's - original - ChumpBot. -

- -

Features

- -

mobibot's main functionality is to - capture URLs posted on the channel. The URLs are automatically gathered into a publishable - RSS feed and saved on Pinboard. -

- -

Other features include:

-
    -
  • Displaying the latest entries on Mobitopia -
    mobibot: view
    -
  • -
  • Performing calculations -
    mobibot: calc (floor(sqrt(3)) + π) * 3^2
    -
  • -
  • Crypto currencies prices -
    mobibot: cryto btc
    -
    mobibot: cryto eth eur
    -
  • -
  • Converting between currencies -
    mobibot: currency 17.54 USD to EUR
    -
  • -
  • Performing Google searches -
    mobibot: google mobitopia on irc
    -
  • -
  • Getting answers from Wolfram Alpha, ChatGPT and Google Gemini -
    mobibot: wolfram days until christmas
    -
    mobibot: chatgpt explain quantum computing in simple terms
    -
    mobibot: gemini what are all the colors in a rainbow?
    -
  • -
  • Displaying weather information -
    mobibot: weather san francisco
    -
    mobibot: weather 94123
    -
    mobibot: weather tokyo, jp
    -
  • -
  • Performing DNS lookups -
    mobibot: lookup www.apple.com
    -
  • -
  • Retrieving stock quotes from Alpha Avantage -
    mobibot: stock GOOG
    -
    mobibot: stock google
    -
  • -
  • Displaying the time in various time zones -
    mobibot: time UK
    -
    mobibot: time GMT
    -
  • -
  • Sending messages to people on join/activity -
    mobibot: tell nickname Give me a call when you see this.
    -
  • -
  • Recapping public channel messages -
    /msg mobibot recap
    -
  • -
  • Listing the users on the channel -
    /msg mobibot users
    -
  • -
  • Viewing when a nickname was last seen -
    /msg mobibot seen nickname
    -
  • -
  • Random jokes from Sv443's JokeAPI -
    mobibot: joke
    -
  • -
  • Playing dice, war or rock paper scissors -
    mobibot: dice
    -
    mobibot: war
    -
    mobibot: paper
    -
    mobibot: rock
    -
  • -
  • Automatic and manual posting to Mastodon -
    mobibot: toot hello mastodon
    -
  • -
-

Some of the internal features include RSS feed backlogs, rolling logs, debugging toggle and much more.

- -

If you have any feature suggestions, please post them to the - mobibot wiki. -

- -

Using mobibot

- -

To use mobibot, simply join #mobitopia on - irc.libera.chat and type: -

- -

mobibot: help

- -

mobibot will reply with a listing of the commands currently supported.

- -

Licenses

- -

There are various open source licenses attached to mobibot. Please refer to the - licenses directory - in the source tree for more details. -

-
- - - diff --git a/website/simple.css b/website/simple.css deleted file mode 100644 index e1204d6..0000000 --- a/website/simple.css +++ /dev/null @@ -1,52 +0,0 @@ -body { - background: #ffffff; - font-family: Verdana, Arial, Helvetica, sans-serif; - font-size: 16px; - color: #000000; - margin: 0; -} - -h1 { - color: #333399; -} - -h2 { - border-bottom: 2px solid #9999cc; -} - -h3 { - padding-top: 25px; - border-bottom: 1px solid #9999cc; -} - -code { - font-family: Courier New, Courier, mono, monospace; - color: #000066; - background-color: #ffeedd; - margin-left: 20px -} - -a:hover { - color: #ff0000; - background: #eeeeff; -} - -#content { - float: none; - position: relative; - margin: 0 10px 10px 10px; - padding: 0 10px 10px 10px; -} - -#content p { - padding-left: 10px; -} - -#content p.note { - padding: 5px; - border: 1px solid #9999cc; - border-right: 2px solid #666699; - border-bottom: 2px solid #666699; - background: #eeeeff; - margin: 20px 50px; -} \ No newline at end of file