diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7690642 --- /dev/null +++ b/.gitignore @@ -0,0 +1,739 @@ + +# Created by https://www.gitignore.io/api/vim,git,java,maven,macos,linux,emacs,eclipse,windows,java-web,code-java,sublimetext,intellij+all,visualstudio,visualstudiocode +# Edit at https://www.gitignore.io/?templates=vim,git,java,maven,macos,linux,emacs,eclipse,windows,java-web,code-java,sublimetext,intellij+all,visualstudio,visualstudiocode + +### Code-Java ### +# Language Support for Java(TM) by Red Hat extension for Visual Studio Code - https://marketplace.visualstudio.com/items?itemName=redhat.java + +.project +.classpath +factoryConfiguration.json + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core + +# JDT-specific (Eclipse Java Development Tools) + +# Annotation Processing +.apt_generated + +.sts4-cache/ + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Intellij+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# 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 +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin + .idea/sonarlint + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Java-Web ### +## ignoring target file +target/ + +### Linux ### + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Maven ### +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +### SublimeText ### +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp_proj +*_wpftmp.csproj +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# End of https://www.gitignore.io/api/vim,git,java,maven,macos,linux,emacs,eclipse,windows,java-web,code-java,sublimetext,intellij+all,visualstudio,visualstudiocode +config.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5a27297 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "configurations": [ + { + "type": "java", + "name": "Mercatino", + "request": "launch", + "mainClass": "io.github.unixmib.mercatino.Main", + "projectName": "mercatino" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8413d19 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "licenser.license": "AGPLv3", + "licenser.projectName": "MercatinoBot", + "licenser.useSingleLineStyle": false, + "licenser.author": "Kowalski7cc", + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/copying.txt b/LICENSE similarity index 97% rename from copying.txt rename to LICENSE index be3f7b2..020d69c 100644 --- a/copying.txt +++ b/LICENSE @@ -1,7 +1,7 @@ GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -29,7 +29,7 @@ with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. - A secondary benefit of defending all users' freedom is that + A secondary benefit of defending all users" freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and @@ -122,7 +122,7 @@ produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's +control those activities. However, it does not include the work"s System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source @@ -164,7 +164,7 @@ your copyrighted material outside their relationship with you. the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + 3. Protecting Users" Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article @@ -176,13 +176,13 @@ measures. circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of +modification of the work as a means of enforcing, against the work"s +users, your or third parties" legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program's source code as you + You may convey verbatim copies of the Program"s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -225,7 +225,7 @@ works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users +used to limit the access or legal rights of the compilation"s users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. @@ -443,7 +443,7 @@ organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could +licenses to the work the party"s predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. @@ -460,9 +460,9 @@ sale, or importing the Program or any portion of it. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". +work thus licensed is called the contributor"s "contributor version". - A contributor's "essential patent claims" are all patent claims + A contributor"s "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, @@ -473,7 +473,7 @@ patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to +patent license under the contributor"s essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. @@ -494,7 +494,7 @@ patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work +covered work in a country, or your recipient"s use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. @@ -525,7 +525,7 @@ or that patent license was granted, prior to 28 March 2007. any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others' Freedom. + 12. No Surrender of Others" Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not @@ -575,7 +575,7 @@ GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's +versions of the GNU Affero General Public License can be used, that proxy"s public statement of acceptance of a version permanently authorizes you to choose that version for the Program. @@ -629,7 +629,7 @@ to attach them to the start of each source file to most effectively state 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 program is free software: you can redistribute it and/or modify @@ -643,7 +643,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -658,4 +658,4 @@ specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see -. +. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..899af84 --- /dev/null +++ b/pom.xml @@ -0,0 +1,189 @@ + + + 4.0.0 + + io.github.unixmib + mercatino + ${maven.build.timestamp}-SNAPSHOT + jar + + Mercatino + Il bot del mercatino di unixMiB + + + unixMiB + https://unixmib.github.io + + + + + github + https://github.com/unixMiB/mercatino/ + default + + + + + https://github.com/unixMiB/mercatino/issues + + + + scm:git:ssh://github.com/unixMiB/mercatino + + + + + Kowalski7cc + kowalski.7cc@xspacesoft.com + https://kowalski7cc.xyz + XSpaceSoft + https://xspacesoft.com + + + + + + GNU Affero General Public License v3.0 + https://www.gnu.org/licenses/agpl.md + repo + + + + + UTF-8 + 11 + 11 + ${maven.build.timestamp} + yyMMdd + + + + ${project.artifactId}-${project.version} + + + maven-compiler-plugin + 3.8.0 + + 11 + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + package + attach-sources + + jar + + + true + true + false + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + true + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + central + https://oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + + javadoc + + jar + + package + + true + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + false + + + + io.github.unixmib.mercatino.Main + + + + + jar-with-dependencies + + + + + + + + + + + com.squareup.okhttp3 + okhttp + 3.12.0 + + + com.xspacesoft.kowalski7cc + BotRevolution + 5.0a-Snapshot + + + junit + junit + 4.12 + test + + + + + + central + https://oss.sonatype.org/content/repositories/snapshots + + + + \ No newline at end of file diff --git a/src/main/java/io/github/unixmib/mercatino/Advertisement.java b/src/main/java/io/github/unixmib/mercatino/Advertisement.java new file mode 100644 index 0000000..91190c5 --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/Advertisement.java @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2019 Kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import com.kowalski7cc.botrevolution.types.User; +import com.kowalski7cc.botrevolution.types.media.PhotoSize; + +import java.util.List; + +public class Advertisement { + + private User owner; + private List photoSizes; + private String title; + private String description; + + public Advertisement(User owner) { + this.owner = owner; + } + + public Advertisement(User owner, List photoSizes, String title, String description) { + this.owner = owner; + this.photoSizes = photoSizes; + this.title = title; + this.description = description; + } + + public User getOwner() { + return owner; + } + + public void setOwner(User owner) { + this.owner = owner; + } + + public List getPhotoSizes() { + return photoSizes; + } + + public void setPhotoSizes(List photoSizes) { + this.photoSizes = photoSizes; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/io/github/unixmib/mercatino/BotLogic.java b/src/main/java/io/github/unixmib/mercatino/BotLogic.java new file mode 100644 index 0000000..b4fd85a --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/BotLogic.java @@ -0,0 +1,226 @@ +/** + * Copyright (C) 2019 Kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import com.kowalski7cc.botrevolution.TelegramBot; +import com.kowalski7cc.botrevolution.types.Message; +import com.kowalski7cc.botrevolution.types.repymarkups.inlinekeyboard.InlineKeyboardBuilder; +import com.kowalski7cc.botrevolution.types.repymarkups.replykeyboards.ReplyKeyboardBuilder; +import com.kowalski7cc.botrevolution.types.repymarkups.replykeyboards.ReplyKeyboardRemove; + +import java.util.Optional; +import java.util.UUID; + +public class BotLogic { + + public static StatesManager load(StatesManager statesManager, TelegramBot telegramBot) { + + statesManager.newState("start", o -> { + telegramBot.sendMessage().setChatID(o.getChat()).setText("Ciao" + o.getFrom() + .map(user -> { + return " " + user.getFirstName(); + }) + .orElse("") + ", benvenuto al mercatino") + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Apri bacheca annunci") + .setUrl("https://t.me/unixmib_mercatino") + .build() + .buildButton("Pubblica annuncio") + .setCallbackData("new_advertisement") + .build() + .build().build()) + .send(); + return "show_hint"; + }); + + statesManager.newState("show_hint", message -> { + telegramBot.sendMessage().setText("Per iniziare a vendere, premi il tasto \"Pubblica annuncio\"") + .setChatID(message.getChat()) + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Apri bacheca annunci") + .setUrl("https://t.me/unixmib_mercatino") + .build() + .buildButton("Pubblica annuncio") + .setCallbackData("new_advertisement") + .build() + .build().build()) + .send(); + return null; + }); + + statesManager.newState("new_advertisement", message -> { + message.getFrom() + .ifPresent(user -> statesManager.store.put("advertisement", new Advertisement(user))); + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Inviami il titolo della tua inserzione") + .send(); + return "read_title"; + }); + + statesManager.newState("read_title", message -> message.getText() + .map(s -> { + getAdvertisementData(statesManager).setTitle(s); + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Aggiungi una descrizione alla tua inserzione") + .send(); + return "read_description"; + }) + .orElseGet(() -> { + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Contenuto non valido, riprova") + .send(); + return null; + })); + + statesManager.newState("read_description", message -> message.getText() + .map(s -> { + getAdvertisementData(statesManager).setDescription(s); + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Allega una foto dell'oggetto che vuoi vendere") + .send(); + return "read_picture"; + }) + .orElseGet(() -> { + telegramBot.sendMessage() + .setText("Contenuto non valido, riprova") + .setChatID(message.getChat()) + .send(); + return null; + })); + + statesManager.newState("read_picture", message -> message.getPhoto() + .map(photoSizes -> { + getAdvertisementData(statesManager).setPhotoSizes(photoSizes); + statesManager.store.put("picture", photoSizes); + telegramBot.sendMessage() + .setText("Ecco una anteprima della tua inserzione") + .setChatID(message.getChat()) + .send(); + telegramBot.sendPhoto() + .setChatID(message.getChat()) + .setCaption(getAdvertisementData(statesManager).getTitle() + "\n" + getAdvertisementData(statesManager).getDescription()) + .setPhoto(photoSizes.get(0) + .getFileID()) + .setReplyMarkup(new ReplyKeyboardBuilder().addRow().buildButton("Pubblica").build() + .buildButton("Annulla").build().build().build()) + .send(); + return "read_publish"; + }) + .orElseGet(() -> message.getDocument() + .map(document -> { + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("La foto non deve essere inviata come file. Riprova allegandola come immagine.") + .send(); + return "read_picture"; + }) + .orElseGet(() -> { + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Contenuto non valido, riprova.") + .send(); + return null; + }))); + + + statesManager.newState("read_publish", message -> message.getText() + .map(s -> Optional.of(s) + .filter(s1 -> s1.equals("Pubblica")) + .map(s1 -> { + var adv = getAdvertisementData(statesManager); + String uuid = UUID.randomUUID().toString(); + DataStore.getAdvertisementMap().put(uuid, adv); + DataStore.getAdmins().forEach(aLong -> { + try { + telegramBot.sendPhoto() + .setChatID(aLong) + .setCaption(adv.getTitle() + "\n" + adv.getDescription()) + .setPhoto(adv.getPhotoSizes().get(0).getFileID()) + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Approva") + .setCallbackData("publish:" + uuid) + .build() + .buildButton("Cancella") + .setCallbackData("delete:"+uuid) + .build() + .build().build()) + .send(); + } catch (Exception e) { + System.out.println("Inpossibile contattare l'admin " + aLong); + } + }); + + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Ottimo. Il tuo annuncio sarà presto pubblicato") + .setReplyMarkup(new ReplyKeyboardRemove()) + .send(); + return "show_hint"; + }) + .or(() -> Optional.of(s).filter(s1 -> s1.equals("Annulla")).map(s1 -> { + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Pubblicazione annullata") + .setReplyMarkup(new ReplyKeyboardRemove()) + .send(); + return "show_hint"; + })) + .orElse(null)) + .orElseGet(() -> { + telegramBot.sendMessage() + .setChatID(message.getChat()) + .setText("Contenuto non valido, riprova.") + .send(); + return null; + })); + + statesManager.newState("bacheca", message -> { + telegramBot.sendMessage().setText("Puoi aprire la bacheca cercando @unixmib_mercatino o premendo il tasto qui sotto") + .setChatID(message.getChat()) + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Apri bacheca annunci") + .setUrl("https://t.me/unixmib_mercatino") + .build().build().build()) + .send(); + return "show_hint"; + }); + + statesManager.newState("abort", message -> { + telegramBot.sendMessage().setText("Azione annullata") + .setChatID(message.getChat()) + .setReplyMarkup(new ReplyKeyboardRemove()) + .send(); + return "show_hint"; + }); + + statesManager.setInitialState("start"); + statesManager.reset(); + + System.out.println(statesManager); + + return statesManager; + } + + private static Advertisement getAdvertisementData(StatesManager statesManager) { + return ((Advertisement) statesManager.store.get("advertisement")); + } +} diff --git a/src/main/java/io/github/unixmib/mercatino/CommandParser.java b/src/main/java/io/github/unixmib/mercatino/CommandParser.java new file mode 100644 index 0000000..44d573e --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/CommandParser.java @@ -0,0 +1,84 @@ +/** + * Copyright (C) 2019 kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import com.kowalski7cc.botrevolution.types.Message; +import com.kowalski7cc.botrevolution.types.MessageEntity; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; + +public class CommandParser { + + private Message message; + + public CommandParser(Message message) { + this.message = Objects.requireNonNull(message); + } + + public Optional getCommand() { + return message.getEntities() + .orElse(Collections.emptyList()) + .stream() + .filter(messageEntity -> messageEntity.getType() + .equals(MessageEntity.MessageEntityType.BOT_COMMAND)) + .map(messageEntity -> message.getText() + .filter(s -> s.length()>messageEntity.getOffset()+messageEntity.getOffset()) + .map(s -> s.substring(messageEntity.getOffset()+1, messageEntity.getOffset()+messageEntity.getLength()))) + .findFirst() + .orElse(Optional.empty()); + } + + public Optional getParameters() { + return getCommand() + .map(s -> message.getText().map(s1 -> Arrays.asList(s1.split(s + " ")))) + .map(strings -> strings.orElse(Collections.emptyList())) + .filter(strings -> strings.size()>1).map(strings -> strings.get(1)); + } + + public void ifPresent(BiConsumer> biFunction) { + getCommand().ifPresent(s -> biFunction.accept(s, getParameters())); + } + + public void ifPresentOrElse(BiConsumer> biFunction, Runnable runnable) { + getCommand().ifPresentOrElse(s -> biFunction.accept(s, getParameters()), runnable); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CommandParser that = (CommandParser) o; + return message.equals(that.message); + } + + @Override + public int hashCode() { + return Objects.hash(message); + } + + @Override + public String toString() { + return "CommandParser{" + + "message=" + message + + '}'; + } +} diff --git a/src/main/java/io/github/unixmib/mercatino/DataStore.java b/src/main/java/io/github/unixmib/mercatino/DataStore.java new file mode 100644 index 0000000..28f157e --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/DataStore.java @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2019 Kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import com.kowalski7cc.botrevolution.TelegramBot; +import com.kowalski7cc.botrevolution.types.Message; +import com.kowalski7cc.botrevolution.types.chat.Chat; +import org.json.JSONObject; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +public class DataStore { + + private static Map> chats; + private static List admins; + private static Map advertisementMap; + private static String board; + public static TelegramBot telegramBot; + + public static void loadDataStore() { + try { + var options = new JSONObject(Files.readAllLines(Paths.get("config.json")).stream().collect(Collectors.joining())); + telegramBot = new TelegramBot(options.getString("token")); + setBoard(options.getString("board")); + setAdmins(options.getJSONArray("admins") + .toList() + .parallelStream() + .map(o -> Long.parseLong(o.toString())) + .collect(Collectors.toList())); + } catch (Exception e) { + telegramBot = new TelegramBot(System.getenv("MERCATINO_TELEGRAM_TOKEN")); + setBoard(System.getenv("MERCATINO_BOARD_ID")); + setAdmins(Optional.ofNullable(System.getenv("MERCATINO_ADMINS_IDS")) + .map(s -> List.of(s.split(":")).parallelStream().map(Long::parseLong).collect(Collectors.toList())) + .orElse(List.of())); + } + + advertisementMap = new HashMap<>(); + chats = new HashMap<>(); + } + + public static Map> getChats() { + return chats; + } + + public static void setChats(Map> chats) { + DataStore.chats = chats; + } + + public static List getAdmins() { + return admins; + } + + public static void setAdmins(List admins) { + DataStore.admins = admins; + } + + public static Map getAdvertisementMap() { + return advertisementMap; + } + + public static void setAdvertisementMap(Map advertisementMap) { + DataStore.advertisementMap = advertisementMap; + } + + public static String getBoard() { + return board; + } + + public static void setBoard(String board) { + DataStore.board = board; + } +} diff --git a/src/main/java/io/github/unixmib/mercatino/Main.java b/src/main/java/io/github/unixmib/mercatino/Main.java new file mode 100644 index 0000000..e61ba07 --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/Main.java @@ -0,0 +1,233 @@ +/** + * Copyright (C) 2019 Kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import com.kowalski7cc.botrevolution.TelegramBot; +import com.kowalski7cc.botrevolution.types.Message; +import com.kowalski7cc.botrevolution.types.Update; +import com.kowalski7cc.botrevolution.types.chat.Chat; +import com.kowalski7cc.botrevolution.types.repymarkups.inlinekeyboard.InlineKeyboardBuilder; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class Main { + + public static void main(String[] args) throws InterruptedException { + printLicense(); + DataStore.loadDataStore(); + DataStore.telegramBot.getReceiver().startPolling(); + DataStore.telegramBot.getMe().ifPresentOrElse(user -> System.out.println("Connected as " + user.getFirstName()), + () -> System.exit(1)); + while (DataStore.telegramBot.getReceiver().isPolling()) { + synchronized (DataStore.telegramBot.getReceiver().getUpdates()) { + DataStore.telegramBot.getReceiver().getUpdates().wait(); + } + + while (!DataStore.telegramBot.getUpdates().isEmpty()) + CompletableFuture.runAsync(() -> apply(DataStore.telegramBot.getUpdates().poll(), DataStore.telegramBot)).join(); + } + } + + private static void printLicense() { + System.out.println("MercatinoBot - unixMiB https://unixmib.github.io/\n" + + "Copyright (C) 2019 Kowalski7cc\n" + + "\n" + + "This program is free software: you can redistribute it and/or modify\n" + + "it under the terms of the GNU Affero General Public License as published by\n" + + "the Free Software Foundation, either version 3 of the License, or\n" + + "(at your option) any later version.\n" + + "\n" + + "This program is distributed in the hope that it will be useful,\n" + + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + + "GNU Affero General Public License for more details.\n" + + "\n" + + "You should have received a copy of the GNU Affero General Public License\n" + + "along with this program. If not, see .\n" + + "---------------------------------------------------------------------------\n"); + } + + private static void apply(Update update, TelegramBot tg) { + System.out.println(update); + + // handle incoming messages + update.getMessage().ifPresent(message -> message.getChat() + .getPrivateChat() + .ifPresent(privateChat -> new CommandParser(message).ifPresentOrElse((command, parameters) -> { + switch (command) { + case "start": + getState(privateChat, tg).reset().apply(message); + break; + case "vendi": + getState(privateChat, tg).reset().jumpToState("new_advertisement").apply(message); + break; + case "help": + getState(privateChat, tg).reset().jumpToState("show_hint").apply(message); + break; + case "bacheca": + getState(privateChat, tg).reset().jumpToState("bacheca").apply(message); + break; + case "annulla": + getState(privateChat, tg).reset().jumpToState("abort").apply(message); + break; + default: + tg.sendMessage().setChatID(message.getChat()).setText("Comando non valido").send(); + break; + } + }, () -> getState(privateChat, tg).apply(message)))); + + update.getCallbackQuery().ifPresent(callbackQuery -> callbackQuery.getData() + .ifPresent(s -> { + var request = s.split(":"); + switch (request[0]) { + case "new_advertisement": + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setCacheTime(10) + .send(); + callbackQuery.getMessage().ifPresent(message -> getState(message.getChat(), tg). + jumpToState("new_advertisement") + .apply(message)); + break; + case "publish": + DataStore.getAdvertisementMap().computeIfAbsent(request[1], s1 -> { + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Annuncio non trovato, probabilmente è già stata effettuata la pubblicazione") + .setCacheTime(1) + .send(); + callbackQuery.getMessage() + .ifPresent(message -> tg.deleteMessage() + .setMessageID(message) + .setChatID(message.getChat()) + .send()); + return null; + }); + DataStore.getAdvertisementMap().computeIfPresent(request[1], (s1, advertisement) -> { + tg.sendPhoto() + .setChatID(DataStore.getBoard()) + .setPhoto(advertisement.getPhotoSizes().get(0).getFileID()) + .setCaption(advertisement.getTitle() + "\n" + advertisement.getDescription()) + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Invia richiesta") + .setCallbackData("contact:" + callbackQuery.getFrom().getId()) + .build() + .build().addRow().buildButton("Gruppo unixMiB") + .setUrl("https://t.me/unixmib").build().build().build()) + .send(); + callbackQuery.getMessage().ifPresent(message -> tg.deleteMessage() + .setChatID(message.getChat()) + .setMessageID(message) + .send()); + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Annuncio pubblicato") + .setCacheTime(1) + .send(); + return null; + }); + break; + case "delete": + DataStore.getAdvertisementMap().computeIfAbsent(request[1], s1 -> { + try { + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Annuncio non trovato, probabilmente è già stata effettuata la pubblicazione") + .setCacheTime(1) + .send(); + callbackQuery.getMessage() + .ifPresent(message -> tg.deleteMessage() + .setMessage(message) + .send()); + return null; + } catch (Exception e) { + return null; + } + }); + DataStore.getAdvertisementMap().computeIfPresent(request[1], (s1, advertisement) -> { + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Annuncio cancellato") + .setCacheTime(1) + .send(); + callbackQuery.getMessage().ifPresent(message -> tg.deleteMessage() + .setChatID(message.getChat()) + .setMessageID(message) + .send()); + return null; + }); + break; + case "contact": + callbackQuery.getFrom().getUsername().ifPresentOrElse(s1 -> { + try { + tg.sendMessage() + .setChatID(request[1]) + .setText("Ciao, hai avuto una richiesta da " + callbackQuery.getFrom() + .getFirstName() + "!") + .setReplyMarkup(new InlineKeyboardBuilder().addRow() + .buildButton("Contattalo subito") + .setUrl("https://t.me/" + s1) + .build() + .build().build()) + .send(); + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Richiesta inviata!") + .setShowAlert(false) + .setCacheTime(10) + .send(); + } catch (Exception e) { + try { + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Errore nella richiesta, probabilmente l'utente non" + + " è più su telegram o ha bloccato il bot") + .setShowAlert(false) + .setCacheTime(10) + .send(); + } catch (Exception e1) { + // oof + } + } + }, () -> tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Accipigna, per poter inviare richieste devi avere un username!") + .setShowAlert(true) + .setCacheTime(10) + .send()); + + break; + default: + tg.answerCallbackQuery() + .setCallbackQueryID(callbackQuery) + .setText("Si è verificato un errore nella richiesta") + .setCacheTime(200) + .setShowAlert(false) + .send(); + break; + } + })); + } + + private static StatesManager getState(Chat chat, TelegramBot telegramBot) { + return DataStore.getChats().compute(chat, (chat1, statesManager) -> Optional.ofNullable(statesManager) + .orElse(BotLogic.load(new StatesManager<>(), telegramBot))); + } + +} \ No newline at end of file diff --git a/src/main/java/io/github/unixmib/mercatino/StatesManager.java b/src/main/java/io/github/unixmib/mercatino/StatesManager.java new file mode 100644 index 0000000..7b04e40 --- /dev/null +++ b/src/main/java/io/github/unixmib/mercatino/StatesManager.java @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2019 Kowalski7cc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.github.unixmib.mercatino; + +import java.util.*; +import java.util.function.Function; + +public class StatesManager { + + private Map> states; + private Function currentState; + private Function initialState; + public Map store; + + public StatesManager() { + states = new HashMap<>(); + store = new HashMap<>(); + initialState = null; + currentState = null; + } + + public StatesManager newState(String name, Function function) { + states.put(name, function); + return this; + } + + public StatesManager setInitialState(String name) { + initialState = states.getOrDefault(name, initialState); + currentState = Optional.ofNullable(currentState).orElse(initialState); + return this; + } + + public StatesManager jumpToState(String state) { + + currentState = states.getOrDefault(state, currentState); + return this; + } + + public StatesManager reset() { + store.clear(); + currentState = initialState; + return this; + } + + public StatesManager apply(Supply supply) { + currentState = Optional.ofNullable(currentState) + .or(() -> Optional.of(initialState)) + .map(supplyStringFunction -> states.getOrDefault(supplyStringFunction.apply(supply), supplyStringFunction)) + .get(); + return this; + } + + public StatesManager removeState(String state) { + states.remove(state); + return this; + } + + @Override + public String toString() { + return "StatesManager{" + + "states=" + states + + ", currentState=" + currentState + + ", initialState=" + initialState + + ", store=" + store + + '}'; + } +} \ No newline at end of file