Compare commits

...

199 Commits

Author SHA1 Message Date
Arthur Poulet 3a3fd6f190
Merge branch 'Lucie-Dispot-master' 2016-05-15 00:04:17 +02:00
Lucie bec6b9436b Added kick and ops plugins 2016-05-14 23:32:54 +02:00
Arthur Poulet 7946dcc9cf strip sent messages 2016-03-26 19:38:33 +01:00
Arthur Poulet 9826602375 add diceroller 2016-03-21 16:30:10 +01:00
Arthur Poulet 4480cabf5a add eip, fix user 2016-03-21 16:19:46 +01:00
Arthur Poulet c588216486 add dep 'i18n' 2015-12-30 22:08:08 +01:00
Arthur Poulet de6f2d82a1 Remove useless assignemnt
close #22
2015-11-28 14:28:32 +01:00
Arthur Poulet 375118ed09 Large improvment for cequetudisnaaucunsens plugin 2015-11-28 14:21:18 +01:00
Arthur Poulet e07d60d03d fix primary email and email from system 2015-11-22 01:42:58 +01:00
Arthur Poulet 36f38abcf0 Improve puppet plugin
- add email system
- improve mail display
- improve privacy
2015-11-21 22:28:37 +01:00
Arthur Poulet b4c3f0d398 fix anecdote 2015-11-21 22:12:41 +01:00
Arthur Poulet 180ea02a76 remove bad joke 2015-11-21 00:33:35 +01:00
Arthur Poulet 9b0a7fe99f Fix readme 2015-11-20 12:51:22 +01:00
Arthur Poulet 44750ae719 add plugin Anecdote to readme 2015-11-20 12:03:26 +01:00
Arthur Poulet 8419a2d383 fix iaa and improve anecdote 2015-11-18 11:37:22 +01:00
Arthur Poulet 415b3c2eb7 fix anecdote 2015-11-18 00:50:55 +01:00
Arthur Poulet 5f6fa860a5 improve anecdote 2015-11-18 00:47:43 +01:00
Arthur Poulet a07a30c858 add anecdote 2015-11-18 00:22:29 +01:00
Arthur Poulet 45fe7b5a07 fix security on iaa 2015-11-18 00:21:56 +01:00
Arthur Poulet 4f49c528af add messaging system 2015-11-13 20:53:54 +01:00
Arthur Poulet efa044b10d fix plugin points (created_at) 2015-11-11 21:54:19 +01:00
Arthur Poulet ea9dc759e9 Improve help plugin (avoid flood)
close #23
2015-11-11 12:17:18 +01:00
Arthur Poulet 6466b590ab update github 2015-10-29 14:46:02 +01:00
Arthur Poulet 5a8e5f8594 improve iaa plugin: prepare data prospection :D 2015-10-23 19:25:16 +02:00
Arthur Poulet 3cca4168a1 Add encryption module 2015-10-22 11:49:17 +02:00
Arthur Poulet 479f24af6a add ep2 to root_me plugin 2015-10-18 18:00:01 +02:00
Arthur Poulet ff1b1a94b1 add root_me 2015-10-18 10:14:24 +02:00
Arthur Poulet 3299e661b2 fix plugin points 2015-10-18 10:12:43 +02:00
Arthur Poulet 37624c27c0 remove homophobic example :') 2015-10-12 23:51:18 +02:00
Arthur Poulet 59e5b813b9 add points nazi 2015-10-12 23:44:45 +02:00
Arthur Poulet 44e98fb7e9 improve plugin points with 2 commands 2015-10-12 01:04:11 +02:00
Arthur Poulet 567458a86e improve points statistics 2015-10-12 00:45:04 +02:00
Arthur Poulet 744714dc14 fix plugin points 2015-10-10 16:29:27 +02:00
Arthur Poulet 544a936457 IAA plugin compare with insensitive case 2015-10-06 21:28:37 +02:00
Arthur Poulet e16c9b9c65 improve points with stats 2015-10-02 17:46:01 +02:00
Arthur Poulet 2167740ad7 fix db points 2015-09-28 18:02:58 +02:00
Arthur Poulet d3a4885f6d fix points 2015-09-27 04:40:21 +02:00
Arthur Poulet 85993f6ac3 fix deps and points 2015-09-27 04:39:31 +02:00
Arthur Poulet cd52ea7077 fix points 2015-09-26 23:49:04 +02:00
Arthur Poulet bc2a7e9aeb improve points 2015-09-26 22:02:42 +02:00
Arthur Poulet 819dfd2520 add readme 2015-09-23 23:13:14 +02:00
Arthur Poulet 57e9e3783e fix cequetu.. 2015-09-23 23:11:15 +02:00
Arthur Poulet a8947da88b add plugin points 2015-09-23 23:07:25 +02:00
Arthur Poulet d41a70caea use authname instead of realname 2015-09-21 18:57:36 +02:00
Arthur Poulet d3fa02c609 add rights for taggle 2015-09-21 18:48:14 +02:00
Arthur Poulet c95614cf94 add plugin apoil 2015-09-20 20:42:51 +02:00
Arthur Poulet e6d200cd33 improve cequetudisnaaucunsens 2015-09-20 01:05:29 +02:00
Arthur Poulet c7c6c219b0 secure authentification
use the user instead of nick for registering / check rights
2015-09-19 23:28:42 +02:00
Arthur Poulet d7b71bbdf2 update README 2015-09-19 21:54:42 +02:00
Arthur Poulet e515d7487d update config example 2015-09-18 23:14:29 +02:00
Arthur Poulet 24b520d702 add cequetudisnaaucunsens 2015-09-18 23:13:48 +02:00
Arthur Poulet 864f066081 fix searchable 2015-08-31 02:08:44 +02:00
Arthur Poulet 3d5e33c638 fix searchable 2015-08-31 02:06:15 +02:00
Arthur Poulet c402c728e0 fix log 2015-08-31 02:01:04 +02:00
Arthur Poulet 8cef10a045 fix log 2015-08-31 01:56:30 +02:00
Arthur Poulet 272c16304f clean lew lines 2015-08-29 17:18:21 +02:00
Arthur Poulet bdd71a0971 fix argument --plugin-disable 2015-08-29 16:47:02 +02:00
Arthur Poulet 8560f933ac remove sqlite from Gemfile 2015-08-26 23:13:09 +02:00
Arthur Poulet f690182021 improve perf with sample instead of shuffle.first 2015-08-24 20:03:53 +02:00
Arthur Poulet 8b7d2722c1 add version 2015-08-24 16:47:20 +02:00
Arthur Poulet 3b410c3fd0 update version, reactivate ENABLED option 2015-08-24 16:43:15 +02:00
Arthur Poulet 012e5d8648 add puppet plugin 2015-08-24 16:20:42 +02:00
Arthur Poulet b6b6dc98a9 update README 2015-08-24 15:56:38 +02:00
Arthur Poulet 8d390c276a fix groups problem 2015-08-24 15:52:04 +02:00
Arthur Poulet 54fe5cb83a fix README link 2015-08-24 15:29:50 +02:00
Arthur Poulet 44d96f2dff add documentation about groups/rights 2015-08-24 15:28:30 +02:00
Arthur Poulet 4bcfa800ee remove breakpoint 2015-08-24 15:26:13 +02:00
Arthur Poulet ea38305df9 Improve rights system
- remove admins from IAA plugin
- add users to Base plugin
- add rights system to Base plugin (with groups)
- update IAA to use Base
- remove Database::Admins extension
- some fixes
2015-08-24 15:21:35 +02:00
Arthur Poulet 55fa5c6ae0 update Gemfiles 2015-08-24 14:49:07 +02:00
Arthur Poulet 116ebbf60b update version 2015-08-19 13:09:05 +02:00
Arthur Poulet 2b83d225a2 fix plugins config 2015-08-19 13:05:45 +02:00
Arthur Poulet 064b09fd76 update contributors list 2015-08-17 17:22:15 +02:00
Arthur Poulet 19621c9962 Merge pull request #19 from Shigugu/patch-1
adding poilo plugin
2015-08-17 16:20:44 +02:00
Shigugu 5bae3bcf42 Merge pull request #1 from Shigugu/patch-2
Create poilo.rb
2015-08-17 16:19:54 +02:00
Shigugu 12ad77ce94 Create poilo.rb 2015-08-17 16:18:00 +02:00
Shigugu ee3374c594 adding some rhymes for poilo plugin 2015-08-17 16:15:41 +02:00
Arthur Poulet c4c227ef2c fix youtube, remove breakpoint 2015-08-17 15:16:10 +02:00
Arthur Poulet 6f6eed76db fix "base", add "youtube" plugins
- fix the plugin "base"
- add the plugin "youtube" to improve youtube research experience
- update configuration
- fix "iamalive" plugin
2015-08-17 08:32:14 +02:00
Arthur Poulet 91223a4b9d fix typo 2015-08-16 13:55:33 +02:00
Arthur Poulet bda19f2f83 Finalize DATABASE EXTENSION readme 2015-08-16 13:40:53 +02:00
Arthur Poulet f30b368f53 fix DBE README 2015-08-16 13:27:14 +02:00
Arthur Poulet 37fae8341d separate db extension (README) 2015-08-16 13:26:26 +02:00
Arthur Poulet d4027cd421 update README
- fix plugin database
- add plugin database admin
2015-08-16 13:22:47 +02:00
Arthur Poulet d7c6a41c22 update README (database extension) 2015-08-16 13:16:10 +02:00
Arthur Poulet fd603c378d large database improvement. add admins extension
- add admin extension to database extension
- update iamalive (use admin extension)
2015-08-16 13:15:27 +02:00
Arthur Poulet c005f42197 update iamalive readme 2015-08-16 05:41:53 +02:00
Arthur Poulet 2e8f9f4983 improve iaa help and sentences 2015-08-16 05:38:53 +02:00
Arthur Poulet 9e7c70a6d6 large "iamalive" plugin
- fix reactivity
- improve forget (can forget the last sentence)
- add get_last
2015-08-16 05:35:15 +02:00
Arthur Poulet 63b4850b11 update example 2015-08-16 05:06:32 +02:00
Arthur Poulet ba97c47b93 improve the database system
add plugin extension "database" (includable)
migrate "iamalive" plugin to use it
2015-08-16 05:05:31 +02:00
Arthur Poulet b574b55192 improve "iamalive" plugin 2015-08-16 04:10:02 +02:00
Arthur Poulet 78b17a113e fix 'iamalive' plugin
fix forget reply
2015-08-16 03:58:10 +02:00
Arthur Poulet 4766c8ad48 little fix on "iamalive" plugin 2015-08-16 03:42:51 +02:00
Arthur Poulet 7c55d6d2f8 improve plugin "iamalive"
improve delete and and the sleep time
2015-08-16 03:36:07 +02:00
Arthur Poulet 42b5289362 Merge pull request #16 from deborahwwilliams/deborahwwilliams-patch-1
Fix typo
2015-08-15 03:09:00 +02:00
Deborah 20416120a8 Fix typo 2015-08-15 02:51:54 +02:00
Arthur Poulet 07139eab6f update modules_config.yml.example / Gemfile+lock 2015-08-15 02:07:33 +02:00
Arthur Poulet b7558d6398 improve "iamalive" plugin
support postgresql for better performances than sqlite
2015-08-15 01:32:36 +02:00
Arthur Poulet 5d8b1eb8c0 improve "iamalive" plugin
memory has 1% loss
2015-08-15 00:24:13 +02:00
Arthur Poulet 3e5092c3dc improve "iamalive" plugin
- add random wait before submitting any message (0-2 seconds)
- fix not allowed commands
2015-08-14 23:59:06 +02:00
Arthur Poulet 8b8ddc3e12 add "!iaa forget X" to "iamalive" plugin 2015-08-14 23:47:26 +02:00
Arthur Poulet e0d6a9a98f fix "iamalive" plugin (rights) 2015-08-14 23:26:04 +02:00
Arthur Poulet 1ba35ed726 improve "iamalive" plugin
add rights to administrate the plugin
2015-08-14 23:04:59 +02:00
Arthur Poulet 87235cdb1b fix "taggle" plugin 2015-08-14 20:28:12 +02:00
Arthur Poulet db1425c242 improve log plugin (matching) 2015-08-14 18:38:31 +02:00
Arthur Poulet d4f9cd3176 improve iamalive and log plugins
- iamalive has now a protection (mutex) to access to the database
- iamalive has configuration to default mode (learn/live)
- log has configuration to default started or not
2015-08-14 18:35:36 +02:00
Arthur Poulet 629d5d71f8 improve "base" plugin
!help plugin does not longer require sensitive case argument
2015-08-14 00:51:45 +02:00
Arthur Poulet 60df899d5a add HELP content to plugin "iamalive" 2015-08-14 00:50:14 +02:00
Arthur Poulet 86344c5c7c add command "!iaa stats" to "iamalive" plugin 2015-08-14 00:48:32 +02:00
Arthur Poulet 1c37dc9777 improve "iamalive" plugin
- add hock before_create to set created_at
2015-08-13 21:59:06 +02:00
Arthur Poulet 0d36f01c72 factorize some code in "iamalive" plugin 2015-08-12 19:15:46 +02:00
Arthur Poulet e738a3b1bf update I am alive README 2015-08-12 19:00:54 +02:00
Arthur Poulet 3e126547f6 fix modes for plugin "iamalive" 2015-08-12 18:31:04 +02:00
Arthur Poulet a4abe96862 improve "iamalive" plugin
- the bot can learn sentence
- the bot can react to a sentence
2015-08-12 18:29:21 +02:00
Arthur Poulet 783a5b7856 improve "iamalive" plugin matching 2015-08-12 17:38:53 +02:00
Arthur Poulet a08d071493 update README 2015-08-12 16:51:08 +02:00
Arthur Poulet 6b4d5816e4 add plugin "iamalive" (not working yet) 2015-08-12 16:48:39 +02:00
Arthur Poulet 18b6a2139c renamed: modules_config.yml -> modules_config.yml.example 2015-08-12 16:10:42 +02:00
Arthur Poulet 8ff39e9a1c update gitignore 2015-08-12 16:09:54 +02:00
Arthur Poulet 3c658d0662 update Gemfile 2015-08-12 15:52:26 +02:00
Arthur Poulet 66357d9e7d fix builtins 2015-08-12 15:35:52 +02:00
Arthur Poulet f2ecfea3c4 update builtins and test 2015-08-12 15:29:01 +02:00
Arthur Poulet 2d6e368f22 update README 2015-08-12 15:01:52 +02:00
Arthur Poulet 67ec98ec9d update README 2015-08-12 14:52:06 +02:00
Arthur Poulet fb6cdf35e8 Improve the config system 2015-08-12 14:44:08 +02:00
Arthur Poulet 77b55cfd55 update BotpopPlugin to Botpop::Plugin 2015-08-12 14:24:45 +02:00
Arthur Poulet 6e16daae66 Merge branch 'v1' 2015-08-12 14:20:47 +02:00
Arthur Poulet 27260c95fe add plugin "proxy" 2015-08-12 14:14:54 +02:00
Arthur Poulet c66cf3e35a update README 2015-08-12 14:12:21 +02:00
Arthur Poulet 2a5b786f26 add "searchable" plugin 2015-08-12 13:56:52 +02:00
Arthur Poulet 0854681ca9 add contributors 2015-08-12 13:52:42 +02:00
Arthur Poulet bb49eb0246 fix plugins inclusion 2015-08-12 01:05:47 +02:00
Arthur Poulet 9e67ec3235 fix taggle 2015-08-12 00:20:52 +02:00
Arthur Poulet a5495fe2ff add "taggle" plugin 2015-08-11 23:57:02 +02:00
Arthur Poulet 691c948612 fix plugin "say_goodbye" 2015-08-11 23:43:10 +02:00
Arthur Poulet d0a1a15a50 fix example.rb 2015-08-11 23:41:12 +02:00
Arthur Poulet 3c537008fe add plugin "say_goodbye" 2015-08-11 23:40:08 +02:00
Arthur Poulet 109b10a71a add plugin "example" and ignore it in inclusion 2015-08-11 23:34:34 +02:00
Arthur Poulet ac0a4539c8 update README 2015-08-11 23:24:05 +02:00
Arthur Poulet 8b5df0eb6f add "log" plugin + fix "base" plugin 2015-08-10 13:09:25 +02:00
Arthur Poulet ed1e1c1078 fix configuration for plugin "base" 2015-08-10 12:59:07 +02:00
Arthur Poulet bd1474fa33 update gitignore 2015-08-10 12:55:38 +02:00
Arthur Poulet 18f3723c72 prepare the v1
- remove old plugins
- update plugins/base
- update the botpop plugins system
2015-08-10 03:05:16 +02:00
Arthur Poulet f9bd99f9bd improve logger to handle concurrential access to logger file 2015-08-09 00:50:46 +02:00
Arthur Poulet f40aaba565 remove log file
what the fuck
2015-08-08 11:43:46 +02:00
Arthur Poulet e9e500dba1 add "!log status" to logger plugin 2015-08-08 11:40:02 +02:00
Arthur Poulet 57d94a87a2 fix logger to log everyone 2015-08-08 11:16:51 +02:00
Arthur Poulet abc20325c9 add !log clean to logger plugin 2015-08-07 18:40:31 +02:00
Arthur Poulet 3c4f90f639 add plugin logger
- add a new plugin: logger, to log a conversation
- add logger config to modules_config.yml
- add logger specific config in logger_user.yml.example
- remove .version.swp
2015-08-07 18:37:23 +02:00
Arthur Poulet 6fb9f10ba0 update gitignore, rename plugin epitech 2015-08-07 18:36:11 +02:00
Arthur Poulet 4f73bac0c0 fix plugin inclusion 2015-08-07 17:20:51 +02:00
Arthur Poulet 8911c21790 update README.md 2015-08-03 21:42:25 +02:00
Arthur Poulet 50a91204bd update Gemfile.lock 2015-08-01 01:36:11 +02:00
Arthur Poulet 68071c459d update gitignore 2015-08-01 01:32:35 +02:00
Arthur Poulet 350f036559 update version 2015-07-27 23:34:40 +02:00
Arthur Poulet 310c355ec3 update readme 2015-07-27 23:32:08 +02:00
Arthur Poulet 4d11212a72 update README. more spaces 2015-07-13 20:58:30 +02:00
Arthur Poulet 064ca480b3 update readme.md 2015-07-13 20:44:56 +02:00
Arthur Poulet 6a8576a35f improve plugin/network architecture 2015-07-13 20:42:07 +02:00
Arthur Poulet f49575fd0e add architecture tests 2015-07-13 20:40:10 +02:00
Arthur Poulet cb32a5902b add global to avoid verbosity on load 2015-07-13 20:35:52 +02:00
Arthur Poulet a2bad76194 add test binding.pry and rakefile for test 2015-07-13 20:31:22 +02:00
Arthur Poulet 41688e2cf6 fix bugs with builtins 2015-07-13 20:23:50 +02:00
Arthur Poulet a14a3b6e97 move the plugin inclusion in specific file 2015-07-12 13:59:32 +02:00
Arthur Poulet f13e1b01bf update README.md 2015-07-12 13:55:41 +02:00
Arthur Poulet f132db05c0 fix default modules_config.yml 2015-07-11 17:52:24 +02:00
Arthur Poulet 1581a8a275 factorize sme code 2015-07-10 18:47:56 +02:00
Arthur Poulet 6ea59df4ce factorize some code 2015-07-10 18:43:57 +02:00
Arthur Poulet c1b8f12877 improve botpop.rb
create some singleton methods to avoid out of method code
2015-07-10 18:26:00 +02:00
Arthur Poulet 4f5337fc9b Improve builtins (set it out of the plugins list) 2015-07-10 18:25:39 +02:00
Arthur Poulet 7746bd6ef6 improve: plugins/base
- add command "!help plugin"
2015-07-10 16:03:00 +02:00
Arthur Poulet 1cf48343e0 Fix searchable module name 2015-07-10 01:40:01 +02:00
Arthur Poulet 74ac860f24 move asteks to sg plugin 2015-06-26 13:52:35 +02:00
Arthur Poulet 01a398e45b remove plugin chapui_s, create say_goodby plugin
Say goodbye plugin say something relative to someone
2015-06-26 13:34:13 +02:00
Arthur Poulet 0ed690ff00 Improve the botpop loading
- manage thrown error
2015-06-26 01:17:16 +02:00
Arthur Poulet ac8eea0779 add few sentences for chapui_s module 2015-06-26 00:36:15 +02:00
Arthur Poulet ea0f6a65a9 improve chapui_s plugin 2015-06-25 23:55:52 +02:00
Arthur Poulet 88870479ba add plugin chapui 2015-06-25 23:44:55 +02:00
Arthur Poulet a68500bc2d Update gemfile.lock, fix "enable" configuration 2015-06-25 23:44:31 +02:00
Arthur Poulet 34ac17d080 Add qwant :) 2015-05-16 19:22:17 +02:00
Arthur Poulet 9f4adc7c07 Fix the doc by adding http:// 2015-05-16 02:06:59 +02:00
Arthur Poulet 006dd51427 increment the wait after a dos 2015-05-16 01:59:32 +02:00
Arthur Poulet feadb76b30 disable epitech by default 2015-05-15 19:56:27 +02:00
Arthur Poulet dea7d8d1f2 Add php and python 2015-05-12 00:50:17 +02:00
Arthur Poulet 6b3987de62 New Feature / Plugins / Multi
- Add plugin Epitech (trolling)
- Add plugin Taggle to spam
2015-05-11 00:20:47 +02:00
Arthur Poulet 02a75d0b61 Add !dicofr 2015-05-10 23:15:28 +02:00
Arthur Poulet 80853b7f7e Little refactorization of network dos, update version 2015-05-10 01:53:36 +02:00
Arthur Poulet 6faa104701 Remove useless comment 2015-05-09 17:08:08 +02:00
Arthur Poulet 2b47232a34 Fix / Plugin / Proxy
Save and preserve locked users, catch Ctrl-C
2015-05-09 17:06:09 +02:00
Arthur Poulet db6798bdb4 Add Proxy to README 2015-05-09 16:49:47 +02:00
Arthur Poulet 2808975acc New Feature / Plugin / Proxy
Add proxy access generator
2015-05-09 16:38:29 +02:00
Arthur Poulet 939f1776ce Fix README and example 2015-05-09 15:36:51 +02:00
Arthur Poulet 6dbbc480f5 Add .codeclimate 2015-05-09 14:45:22 +02:00
Arthur Poulet 265dd7cd14 Improv / Plugin / Coupons
Improve coupon. It match with every coupons every times, even multiple in the same msg
2015-05-09 14:08:02 +02:00
Arthur Poulet cc8183c859 Improv / Plugin / Network
Improve the trace (lisibility)
2015-05-09 13:42:24 +02:00
Arthur Poulet 7d9c3c8e9c Improv / Plugin / Network
Configure trace
2015-05-09 13:36:07 +02:00
Arthur Poulet ec4b8f3d9c Feature / Plugin / Network
Fix configuration
2015-05-09 13:31:12 +02:00
Arthur Poulet 21dd8eead7 Add base and network configuration 2015-05-09 13:29:28 +02:00
Arthur Poulet 6fcd33bab6 Improv / Plugin / Coupons
minor improvment
2015-05-09 13:18:57 +02:00
63 changed files with 2235 additions and 553 deletions

3
.codeclimate.yml Normal file
View File

@ -0,0 +1,3 @@
languages:
Ruby: true
exclude_paths: []

11
.gitignore vendored
View File

@ -1 +1,10 @@
up
*.swp
*~
*.log
*.sqlite3
old/
modules_config.yml
plugins/log_user.yml

78
DATABASE_EXTENSION.md Normal file
View File

@ -0,0 +1,78 @@
# Database Extension
## Plugin Database Extension
You can configure a database to store a large amount of volatiles informations,
like the users rights, etc.
To do it, there is an extension, ready to be used.
### 1. configure the database access
for exemple, in the ``modules_config.yml``:
```yaml
plugin:
database:
adapter: postgres
host: localhost
port: 5432
user: root
password: toor
database: botpop_db
```
*note: you can also configure it in a specific database file.
In these case, adapt the following code.*
Then, in you plugin, add the following code:
```ruby
class Plugin < Botpop::Plugin
include Cinch::Plugin
include Botpop::Plugin::Database # include the extension
...
if ENABLED
DB_CONFIG = self.db_config = config(safe: true)['database']
DB = self.db_connect!
require_relative 'plugin/model' # if you have a model, include it now
end
end
```
### 2. create the database and tables
It can be done via 2 ways:
- migrations: **recommanded**.
This is safer and more reliable.
There is an example in the plugin [iamalive](plugins/iamalive/).
Checkout the documentation of the orm:
[sequel migrations](http://sequel.jeremyevans.net/rdoc/files/doc/migration_rdoc.html).
- manual: **NOT recommanded**.
Create the database and tables manually.
### 3. use it
You can access to the database via the constant ``DB``
```ruby
class Plugin ...
...
def search_word m, word
found = DB[:words].where(word: word).first
m.reply found ? found[:id] : 'no such word'
end
end
```
### 4. models
If you want to use models, don't forget to set the "dataset"
(association with the right database / table)
to avoid conflicts:
```ruby
class Model < Sequel::Model
set_dataset DB[:admins]
end
```

25
Gemfile
View File

@ -1,6 +1,29 @@
source 'https://rubygems.org'
gem 'net-ping'
#irc
gem 'cinch'
# scrap yt
gem 'mechanize'
# debug
gem 'pry'
gem 'colorize'
#network
gem 'net-ping'
#proxy
gem 'htauth'
#iamalive
gem 'sequel'
# gem 'sqlite3'
gem 'pg'
#encrypt
gem 'tor257'
#other
gem 'nomorebeer'
gem 'i18n'

View File

@ -1,16 +1,47 @@
GEM
remote: https://rubygems.org/
specs:
cinch (2.2.5)
cinch (2.2.7)
coderay (1.1.0)
colorize (0.7.7)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
htauth (2.0.0)
http-cookie (1.0.2)
domain_name (~> 0.5)
i18n (0.7.0)
mechanize (2.7.3)
domain_name (~> 0.5, >= 0.5.1)
http-cookie (~> 1.0)
mime-types (~> 2.0)
net-http-digest_auth (~> 1.1, >= 1.1.1)
net-http-persistent (~> 2.5, >= 2.5.2)
nokogiri (~> 1.4)
ntlm-http (~> 0.1, >= 0.1.1)
webrobots (>= 0.0.9, < 0.2)
method_source (0.8.2)
net-ping (1.7.7)
pry (0.10.1)
mime-types (2.6.2)
mini_portile (0.6.2)
net-http-digest_auth (1.4)
net-http-persistent (2.9.4)
net-ping (1.7.8)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
nomorebeer (1.1)
ntlm-http (0.1.1)
pg (0.18.3)
pry (0.10.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
sequel (4.27.0)
slop (3.6.0)
tor257 (0.2)
nomorebeer (~> 1.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
webrobots (0.1.1)
PLATFORMS
ruby
@ -18,5 +49,15 @@ PLATFORMS
DEPENDENCIES
cinch
colorize
htauth
i18n
mechanize
net-ping
nomorebeer
pg
pry
sequel
tor257
BUNDLED WITH
1.11.2

139
README.md
View File

@ -1,10 +1,29 @@
# botpop
[![Code Climate](https://codeclimate.com/github/pouleta/botpop/badges/gpa.svg)](https://codeclimate.com/github/pouleta/botpop)
[![Code Climate](https://codeclimate.com/github/Nephos/botpop/badges/gpa.svg)](https://codeclimate.com/github/Nephos/botpop)
[![GitHub version](https://badge.fury.io/gh/Nephos%2Fbotpop.svg)](http://badge.fury.io/gh/Nephos%2Fbotpop)
## Usage
## Requirements
- Ruby 2.0 or greater
- Postgresql 9.3 or greater
## Installation
Ruby 2 or greater is required. To be compatible with Ruby 1.9, you can try :
``sed 's/prepend/include/g' -i botpop.rb`` but no garanties...
``bundle install`` to install the gems.
```bash
sed 's/prepend/include/g' -i botpop.rb
```
but i did never try... You better update ruby ! ;)
Too install the stuff, just do :
```bash
bundle install # install the required gems
cp modules_config.yml.example modules_config.yml
editor modules_config.yml # set the database settings, etc.
# create your database
rake db:install # migrate the base plugin
```
## Arguments
@ -20,13 +39,14 @@ By default, only the first occurence of the argument will be used, unless specif
- --plugin-disable _OPTION_ : disable a plugin (can be specified many times)
- --debug, -d _OPTION_ : enable the debug mod. It et a global __$debug_OPTION__ to true. (can be specified many times)
### Debugging easier
You can specify the --debug OPT option at program start.
It will define as many __$debug_OPT__ globals to enable debug on the plugins.
As example:
```ruby
# If debug enabled for this options and error occured
# If debug enabled for this options and error occured
if $debug_plugin and variable == :failed
binding.pry # user hand here
# Obsiously, it is usefull to trylock a mutex before because the bot use
@ -34,15 +54,26 @@ if $debug_plugin and variable == :failed
end
```
# Plugins
Some official plugins are developped. You can propose your own creation by pull request, or add snippets link to the wiki.
## List
- [Base](https://github.com/pouleta/botpop/blob/master/plugins/base.rb) : this is a basic plugin, providing __version, code, help, and troll__
- [Network](https://github.com/pouleta/botpop/blob/master/plugins/network.rb) : an usefull plugin with commands __ping, ping ip, ping http, traceroute, dos attack and poke__
- [Searchable](https://github.com/pouleta/botpop/blob/master/plugins/searchable.rb) : a little plugin providing irc research with engines like __google, wikipedia, ruby-doc, etc...__
- [Coupon](https://github.com/pouleta/botpop/blob/master/plugins/coupons.rb) : the original aim of the bot. It get coupons for the challenge __pathwar__
- [Intranet](https://github.com/pouleta/botpop/blob/master/plugins/intranet.rb) : an useless plugin to check the intranet of epitech
- [Base](https://github.com/Nephos/botpop/blob/master/plugins/base.rb) : this is a basic plugin, providing __version, code, help, and troll__. It also provide a full groups's system.
- [Network](https://github.com/Nephos/botpop/blob/master/plugins/network.rb) : an usefull plugin with commands __ping, ping ip, ping http, traceroute, dos attack and poke__
- [Searchable](https://github.com/Nephos/botpop/blob/master/plugins/searchable.rb) : a little plugin providing irc research with engines like __google, wikipedia, ruby-doc, etc...__
- [Proxy](https://github.com/Nephos/botpop/blob/master/plugins/proxy.rb) : an audacious plugin to create user access to a local proxy
- [Log](https://github.com/Nephos/botpop/blob/master/plugins/log.rb) : simple logger
- [IAmAlive](https://github.com/Nephos/botpop/tree/master/plugins/iamalive) : a plugin to learn how to respond to the users. Fucking machine learning, oh yearh.
- [CeQueTuDisNaAucunSens](https://github.com/Nephos/botpop/tree/master/plugins/cequetudisnaaucunsens.rb) : a funny plugin to say "ce que tu dis n'a aucun sens" without any meaning.
- [Points](https://github.com/Nephos/botpop/tree/master/plugins/points.rb) : a gem to add points to an user. ``!p noob for_you``
- [Anecdote](https://github.com/Nephos/botpop/blob/master/plugins/anecdote.rb) : a cool meme generator plugin with nazi and youtuber. French meme.
### In version 0.X, not upgraded to v1
- [Coupon](https://github.com/Nephos/botpop/blob/master/plugins/coupons.rb) : the original aim of the bot. It get coupons for the challenge __pathwar__
- [Intranet](https://github.com/Nephos/botpop/blob/master/plugins/intranet.rb) : an useless plugin to check the intranet of epitech
## Create your own
You can easy create your own plugins.
@ -50,60 +81,96 @@ You can easy create your own plugins.
The bot is based on [Cinch framework](https://github.com/cinchrb/cinch/).
You should take the time to read the documentation before developping anything.
### Example of new plugin
A full example of plugin code is provided in the commented file : [Example of Fury Plugin](https://github.com/pouleta/botpop/blob/master/plugins/example.rb)
A full example of plugin code is provided in the commented file : [Example of Fury Plugin](https://github.com/Nephos/botpop/blob/master/plugins/example.rb)
First, put your ruby code file in ``plugins/``, and put your code in the scope :
```ruby
module BotpopPlugins
module MyFuryPlugin
def self.exec_whatkingofanimal m
m.reply "Die you son of a" + ["lion", "pig", "red panda"].shuffle.first + " !!"
end
...code...
class MyFuryPlugin < Botpop::Plugin
include Cinch::Plugin
def exec_whatkingofanimal m
m.reply "Die you son of a" + ["lion", "pig", "red panda"].sample + " !!"
end
...code...
end
```
### Matching messages
To create a matching to respond to a message, you have to specifie in your plugin :
```ruby
module BotpopPlugins
module MyFuryPlugin
MATCH = lambda do |parent|
parent.on :message, /!whatkingofanimal.*/ do |m| BotpopPlugins::exec_whatkingofanimal m end
end
...code...
end
class MyFuryPlugin < Botpop::Plugin
include Cinch::Plugin
match(/!whatkingofanimal.*/, use_prefix: false, method: :exec_whatkingofanimal)
...code...
end
```
### Add entry to the !help command
The __official plugin__ [Base](https://github.com/pouleta/botpop/blob/master/plugins/base.rb) provides the command __!help__.
The __official plugin__ [Base](https://github.com/Nephos/botpop/blob/master/plugins/base.rb) provides the command __!help__ and __!help plugin__.
It list the avaliable commands of the plugins. You can add your help to your plugin by providing a __HELP__ constant.
__The strings should be as short as possible.__
You should write it like the following:
```ruby
module BotpopPlugins
module MyFuryPlugin
HELP = ["!whatkingofanimal", "!animallist", "!checkanimal [type]"]
...code...
end
class MyFuryPlugin < Botpop::Plugin
HELP = ["!whatkingofanimal", "!animallist", "!checkanimal [type]"]
...code...
end
```
### Enable and disable plugin
You can enable or disable plugin by using the constant __ENABLED__.
It should be linked with the __Botpop::CONFIG__.
The constant must be defined by the developper of the plugin.
For example, you can implement it like :
```ruby
module BotpopPlugins
module MyFuryPlugin
CONFIG = Botpop::CONFIG['myfurry'] || raise(MissingConfigurationZone, 'myfurry')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
end
class MyFuryPlugin < Botpop::Plugin
ENABLED = config['enable'].nil? ? true : config['enable']
end
```
Then, a simple line in the ``modules_configuration.yml`` file should be enough.
### Plugin Configuration
You can configure your plugins via the file ``modules_configuration.yml``.
If you considere that your plugin needs a particular configuration file, then create a new one il the ``plugins`` directory.
To use the configuration loaded by ``modules_configuration.yml``, use the method ``config``.
``config`` takes an optionnal Hash as argument. It can take:
- ``:safe => (true or false)``
- ``:name => (string or symbol)``
This method returns a Hash with configuration.
By default, the method raise a ``MissingConfigurationZone`` error if no entry in the ``modules_configuration.yml`` file.
The configuration file ``modules_configuration.yml`` must seems like :
```yaml
name:
entry: "string"
entry2:
- 1
- 2.2
- "ohoh"
- nextelement:
- oh oh !
```
By default, the ``modules_configuration.yml`` file is configured for default plugins.
### Plugin Database
Check this specified [README FOR DATABASE IN PLUGINS](DATABASE_EXTENSION.md)
### Rights managements (users, groups)
Requires postgresql, because it uses the pg_array extension.
Check this specified [README FOR RIGHTS MANAGEMENT](RIGHTS_MANAGEMENT.md)

15
RIGHTS_MANAGEMENT.md Normal file
View File

@ -0,0 +1,15 @@
# How to use rights ?
In your plugin, add the method ``cmd_allowed?`` and use it like in the following example:
```ruby
class Plugin < Botpop::Plugin
...
def cmd_allowed? m
return if not Base.cmd_allowed? m, ["groupname"]
end
def exec_some_match m
return Base.cmd_allowed? m, ["iaa"]
end
```

17
Rakefile Normal file
View File

@ -0,0 +1,17 @@
#encoding: utf-8
require 'yaml'
CONFIG = YAML.load_file("modules_config.yml")
#require 'sequel'
#DB_BASE = Sequel.connect(CONFIG['base']['database'])
#task :default => ["x:x"]
namespace :db do
task :install do
# TODO: use CONFIG['base']
`sequel -m plugins/base/migrations postgres://root:toor@localhost:5432/botpop_base`
end
end

View File

@ -1,8 +1,8 @@
# encoding: utf-8
class Arguments
# @arg : name [String] the option to search
# @arg : name [Array] the options to search (multiples keys avaliables)
# @param name [String] the option to search
# @param name [Array] the options to search (multiples keys avaliables)
def get_one_argument(name, default_value)
if name.is_a? String
i = @argv.index(name)
@ -83,17 +83,13 @@ class Arguments
end
def disable_plugins
i = 0
plugins = []
argv = @argv.dup
while i
loop do
i = argv.index('--plugin-disable')
if i
plugin = argv[i + 1]
plugin = plugin + '.rb' if plugin[-4..-1] != '.rb'
plugins << File.expand_path(plugin, plugin_directory)
argv = argv[(i+2)..(-1)]
end
break unless i
plugins << @argv[i + 1]
argv = argv[(i+2)..(-1)]
end
return plugins
end

View File

@ -13,43 +13,55 @@ require 'yaml'
require 'colorize'
require_relative 'arguments'
require_relative 'builtin'
$botpod_arguments ||= ARGV
require_relative 'botpop_plugin_inclusion'
require_relative 'builtins'
require_relative 'database'
class Botpop
# FIRST LOAD THE CONFIGURATION
ARGUMENTS = Arguments.new($botpod_arguments)
VERSION = IO.read('version')
CONFIG = YAML.load_file(ARGUMENTS.config_file)
TARGET = /[[:alnum:]_\-\.]+/
# THEN INCLUDE THE PLUGINS (STATE MAY BE DEFINED BY THE PREVIOUS CONFIG)
Dir[File.expand_path '*.rb', ARGUMENTS.plugin_directory].each do |f|
if !ARGUMENTS.disable_plugins.include? f
puts "Loading plugin file ... " + f.green + " ... " + require_relative(f).to_s
class Plugin
def self.config(infos={})
name = (infos[:name] || self.to_s.downcase).to_s
config = Botpop::CONFIG[name]
return config || (raise(MissingConfigurationZone, self.to_s) unless infos[:safe])
end
end
# THEN LOAD / NOT THE PLUGINS
@@plugins = []
BotpopPlugins.constants.each do |const|
plugin = BotpopPlugins.const_get(const)
next if not plugin.is_a? Module
if plugin::ENABLED == false
puts "Disabled plugin #{plugin}".yellow
next
end rescue nil
puts "Load plugin #{plugin}".green
prepend plugin
@@plugins << plugin
def self.load_version
begin
return IO.read('version')
rescue Errno::ENOENT
puts "No version specified".red
return "???"
end
end
def self.plugins
@@plugins.dup
def self.include_plugins
PluginInclusion.plugins_include! ARGUMENTS
end
def self.load_plugins
Module.constants.select{ |m|
(m = Module.const_get(m) rescue false) and
(m.is_a?(Class)) and
(m.ancestors.include?(Plugin)) and
(m.included_modules.include?(Cinch::Plugin))
}.
select{|m| not ARGUMENTS.disable_plugins.include? m.to_s
}.
map{|m| Module.const_get(m)
}.
select{|m| m::ENABLED}
end
# FIRST LOAD THE CONFIGURATION
ARGUMENTS = Arguments.new(ARGV)
VERSION = load_version()
CONFIG = YAML.load_file(ARGUMENTS.config_file)
TARGET = /[[:alnum:]_\-\.]+/
include_plugins()
PLUGINS = load_plugins()
def start
@engine.start
end
@ -63,10 +75,7 @@ class Botpop
c.port = ARGUMENTS.port
c.user = ARGUMENTS.user
c.nick = ARGUMENTS.nick
end
@@plugins.each do |plugin|
puts "Load matchings of the plugin #{plugin}".green
plugin::MATCH.call(self, plugin) rescue puts "No matching found for #{plugin}".red
c.plugins.plugins = PLUGINS
end
end
end
@ -74,5 +83,11 @@ class Botpop
end
if __FILE__ == $0
Botpop.new.start
$bot = Botpop.new
trap("SIGINT") do
puts "\b"
puts "SIGINT Catched"
exit
end
$bot.start
end

View File

@ -0,0 +1,35 @@
#!/usr/bin/env ruby
#encoding: utf-8
module PluginInclusion
def self.plugin_error_failure! e, f
STDERR.puts "Error during loading the file #{f}".red
STDERR.puts "#{e.class}: #{e.message}".red.bold
STDERR.puts "---- Trace ----"
STDERR.puts e.backtrace.join("\n").black.bold
exit 1
end
def self.plugin_include! f
return false if File.basename(f) == "example.rb"
begin
if $botpop_include_verbose != false
puts "Loading plugin file ... " + f.green + " ... " + require_relative(f).to_s
else
require_relative(f)
end
rescue => e
plugin_error_failure! e, f
end
end
# THEN INCLUDE THE PLUGINS (STATE MAY BE DEFINED BY THE PREVIOUS CONFIG)
def self.plugins_include! arguments
Dir[File.expand_path '*.rb', arguments.plugin_directory].each do |f|
if !arguments.disable_plugins.include? f
plugin_include! f
end
end
end
end

View File

@ -1,7 +1,7 @@
# encoding: utf-8
module BotpopPlugins
module Builtin
class Botpop
module Builtins
def self.dos(ip, duration)
`timeout #{duration} hping --flood '#{ip}' 2>&1`

View File

@ -3,3 +3,5 @@ moul -- guest
ernestjkaufman -- guest
FolenScare -- guest
JoycePF -- guest
Deborah -- guest
Shigugu -- guest

21
database.rb Normal file
View File

@ -0,0 +1,21 @@
#coding: utf-8
class Botpop
class Plugin
module Database
def self.append_features(b)
b.extend self
end
attr_accessor :db_config
attr_reader :db
def db_connect!
require 'sequel'
@db = Sequel.connect(@db_config)
@db
end
end
end
end

View File

@ -1,51 +0,0 @@
searchable:
yt: https://www.youtube.com/results?search_query=___MSG___
xv: http://www.xvideos.com/?k=___MSG___
yp: https://www.youporn.com/search/?query=___MSG___
gh: https://github.com/search?q=___MSG___&type=Code&utf8=%E2%9C%93
code: http://rosettacode.org/mw/index.php?search=___MSG___&title=Special%3ASearch
cpp: http://www.cplusplus.com/search.do?q=___MSG___
tek: https://intra.epitech.eu/user/___MSG___
archfr: https://wiki.archlinux.fr/index.php?title=Sp%C3%A9cial%3ARecherche&search=___MSG___
arch: https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=___MSG___&go=Go
gl: https://gitlab.com/search?utf8=%E2%9C%93&search=___MSG___&group_id=&repository_ref=
map: https://www.google.fr/maps/search/___MSG___
rb: ruby-doc.com/search.html?q=___MSG___&sa=Search
ror: https://github.com/rails?utf8=%E2%9C%93&query=___MSG___
actu: https://www.google.fr/search?hl=fr&gl=fr&tbm=nws&authuser=0&q=___MSG___
news: https://www.google.fr/search?hl=fr&gl=fr&tbm=nws&authuser=0&q=___MSG___
tw: https://twitter.com/search?q=___MSG___
w: https://en.wikipedia.org/wiki/Special:Search?&go=Go&search=___MSG___
wfr: https://fr.wikipedia.org/wiki/Special:Search?search=___MSG___&go=Go
ddg: https://duckduckgo.com/?q=___MSG___
g: https://encrypted.google.com/search?hl=en&q=___MSG___
lmsfy: http://lmgtfy.com/?q=___MSG___
search: http://lmgtfy.com/?q=___MSG___
s: http://lmgtfy.com/?q=___MSG___
buy: http://www.ebay.com/sch/i.html?_from=R40&_trksid=m570.l1313&_nkw=___MSG___&_sacat=0
amazon: http://www.amazon.fr/s?url=search-alias=aps&field-keywords=___MSG___&tag=a2appw-21
pkmn: http://pokemondb.net/search?q=___MSG___
paste: pastebin.com/search?ie=UTF-8&q=___MSG___
base:
enabled: true
network:
duration: 2s
wait: 5s # Can be in ms or s
intranet:
enabled: true
network:
enabled: true
coupons:
enabled: true
iamalive:
enable: false
database_file: plugins/iamalive.database.yaml
example:
enabled: false

161
modules_config.yml.example Normal file
View File

@ -0,0 +1,161 @@
base:
enable: true
help_wait_duration: 120
database:
adapter: postgres
host: localhost
port: 5432
user: root
password: toor
database: botpop_base
dice:
enable: true
eip:
enable: true
rootme:
enable: false
points:
enable: true
anecdote:
enable: true
log:
enable: true
default_started: false
encrypt:
enable: true
puppet:
enable: true
taggle:
enable: true
ntimes: 10
wait: 0.3
youtube:
enable: true
display: "Youtube: ___TITLE___ ___URL___"
reduce_url: https://youtu.be/___ID___
search_url: https://www.youtube.com/results?search_query=___MSG___
poilo:
enable: false
list:
u: cul
a: bras
o: dos
i: kiki
eu: lepreux
y: nazi
oi: petit-pois
eau: bébé oiseau
au: marmot
ou: doudou
an: manant
searchable:
#yt: https://www.youtube.com/results?search_query=___MSG___ # use the plugin youtube instead
xv: http://www.xvideos.com/?k=___MSG___
yp: https://www.youporn.com/search/?query=___MSG___
paste: https://pastebin.com/search?ie=UTF-8&q=___MSG___
gh: https://github.com/search?q=___MSG___&type=Code&utf8=%E2%9C%93
gl: https://gitlab.com/search?utf8=%E2%9C%93&search=___MSG___
code: http://rosettacode.org/mw/index.php?search=___MSG___&title=Special%3ASearch
cpp: http://www.cplusplus.com/search.do?q=___MSG___
rb: https://ruby-doc.com/search.html?q=___MSG___&sa=Search
ror: https://github.com/rails?utf8=%E2%9C%93&query=___MSG___
php: https://php.net/manual-lookup.php?pattern=___MSG___
python: https://www.python.org/search/?q=___MSG___
archfr: https://wiki.archlinux.fr/index.php?title=Sp%C3%A9cial%3ARecherche&search=___MSG___
arch: https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=___MSG___&go=Go
map: https://www.google.fr/maps/search/___MSG___
actu: https://www.google.fr/search?hl=fr&gl=fr&tbm=nws&authuser=0&q=___MSG___
news: https://www.google.fr/search?hl=fr&gl=fr&tbm=nws&authuser=0&q=___MSG___
tw: https://twitter.com/search?q=___MSG___
dicofr: https://fr.wiktionary.org/wiki/___MSG___
w: https://en.wikipedia.org/wiki/Special:Search?&go=Go&search=___MSG___
wfr: https://fr.wikipedia.org/wiki/Special:Search?search=___MSG___&go=Go
ddg: https://duckduckgo.com/?q=___MSG___
q: https://prev.qwant.com/?q=___MSG___
g: https://encrypted.google.com/search?hl=en&q=___MSG___
lmsfy: http://lmgtfy.com/?q=___MSG___
search: http://lmgtfy.com/?q=___MSG___
s: http://lmgtfy.com/?q=___MSG___
buy: http://www.ebay.com/sch/i.html?_from=R40&_trksid=m570.l1313&_nkw=___MSG___&_sacat=0
amazon: http://www.amazon.fr/s?url=search-alias=aps&field-keywords=___MSG___&tag=a2appw-21
pkmn: http://pokemondb.net/search?q=___MSG___
tek: https://intra.epitech.eu/user/___MSG___
network:
enable: true
dos_wait: 10s
dos_duration: 3s
trace_duration_init: 0.3s
trace_duration_incr: 0.1s
proxy:
enable: false
ip_addr: localhost
ip_port: 0
limit_users: 4
passwd_file: /tmp/squid3_passwords
epitech:
enable: false
iamalive:
enable: true
default_mode: live
database:
adapter: postgres
host: localhost
port: 5432
user: root
password: toor
database: botpop_iamalive
cequetudisnaaucunsens:
enabled: true
saygoodbye:
chapui_s:
- "@chapui_s t'es là ?"
- "chapui_s !!! T'es où ?"
- "Chapuis ?"
- "Hey chapuis !!"
- "Chapui, viens ici !"
- "chapui_s, j'ai mis register const int i en global ! :)"
- "Chapuis, j'ai trouvé une faille dans gdb"
- "Hey seb ! J'ai remis le t_server en global"
- "Chapuis ! J'ai recodé printf en asm"
- "Chapuis, mon pc il est en 32 ou 64 bits ?"
- "Chapui, tu me fais mon corewar stp ?"
- "Sebastien, comment on swap 2 int en version opti ?"
- "Seb, comment tu te fais respecter ?"
- "@chapui_s, viens on a besoin de toi"
- "@chapui_s t'as soutenance dans 15 minutes au fait"
- "Chapuis, comment on fait un const cast"
asteks:
- "Faut surtout pas lock les mutexes !!! oO Après tu peux deadlock !"
- "J'ai ubuntu pourquoi ?"
- "C'est l'histoire d'un astek qui voulait installer Archlinux..."
- "Ouais nan mais système unix avancé c'est chiant, ça sert à rien en fait..."
- "Nan mais, on peut pas faire le 42sh et le Raytracer en même temps, c'est trop dur."
- "T'as triché. T'as regardé du code un jour en salle, et tu l'as imprimé dans ta tête"
jacob_f:
- "No râge de mon gradÂge !"
poulet_a:
- "Nan mais c'est un scandale ! Pourquoi j'ai grade A ?"

2
plugins/.gitignore vendored
View File

@ -1,2 +0,0 @@
coupon_login.yml
iamalive.database.yaml

46
plugins/anecdote.rb Normal file
View File

@ -0,0 +1,46 @@
require 'nokogiri'
require 'net/http'
class Anecdote < Botpop::Plugin
include Cinch::Plugin
match(/!a(necdote)? (.+)/, use_prefix: false, method: :exec_new)
HELP = ["!anecdote <...>"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def exec_new m, _, s
s.downcase!
f = I18n.transliterate(s)[0]
x = "Après je vous propose "
x += (%w(a e i o u y).include?(f) ? "d'" : "de ") if not s.match(/^(d'|de ).+/)
s = x + s
url = URI.parse 'http://memegenerator.net/create/instance'
post_data = {
'imageID' => 14185932,
'generatorID' => 5374051,
'watermark1' => 1,
'uploadtoImgur' => 'true',
'text0' => s,
'text1' => "Ca fera une petite anecdote !!",
}
meme = nil
begin
Net::HTTP.start url.host do |http|
post = Net::HTTP::Post.new url.path
post.set_form_data post_data
res = http.request post
location = res['Location']
redirect = url + location
get = Net::HTTP::Get.new redirect.request_uri
res = http.request get
doc = Nokogiri.HTML res.body
meme = doc.css("meta")[7]['content']
end
rescue => _err
end
m.reply meme ? meme : "Achtung ! ACHTUUUUNG !!!"
end
end

View File

@ -1,64 +1,85 @@
#encoding: utf-8
module BotpopPlugins
module Base
require "i18n"
I18n.config.available_locales = [:en, :fr]
MATCH = lambda do |parent, plugin|
parent.on :message, /!troll .+/ do |m| plugin.exec_troll m end
parent.on :message, "!version" do |m| plugin.exec_version m end
parent.on :message, "!code" do |m| plugin.exec_code m end
parent.on :message, "!cmds" do |m| plugin.exec_help m end
parent.on :message, "!help" do |m| plugin.exec_help m end
end
HELP = ["!troll [msg]", "!version", "!code", "!help", "!cmds"]
CONFIG = Botpop::CONFIG['base'] || raise(MissingConfigurationZone, 'base')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
class Base < Botpop::Plugin
include Cinch::Plugin
include Botpop::Plugin::Database
def self.help_wait_before_quit
HELP_WAIT_DURATION.times do
sleep 1
@help_time += 1
end
end
match(/^!troll .+/ , use_prefix: false, method: :exec_troll)
match "!version" , use_prefix: false, method: :exec_version
match "!code" , use_prefix: false, method: :exec_code
match "!cmds" , use_prefix: false, method: :exec_help
match "!help" , use_prefix: false, method: :exec_help
match(/^!help \w+/ , use_prefix: false, method: :exec_help_plugin)
def self.help_get_plugins_str
["Plugins found : " + Botpop.plugins.size.to_s] +
Botpop.plugins.map do |plugin|
plugin.to_s.split(':').last + ': ' + plugin::HELP.join(', ') rescue nil
end.compact
end
match("!register", use_prefix: false, method: :user_register)
match("!user ls", use_prefix: false, method: :user_ls)
match(/^!user (\w+) group ls$/, use_prefix: false, method: :user_group_ls)
match(/^!user (\w+) group add (\w+)/, use_prefix: false, method: :user_group_add)
match(/^!user (\w+) group rm (\w+)/, use_prefix: false, method: :user_group_rm)
HELP_WAIT_DURATION = 120
def self.help m
@help_lock ||= Mutex.new
if @help_lock.try_lock
@help_time = 0
help_get_plugins_str().each{|str| m.reply str} # display
help_wait_before_quit rescue nil
@help_lock.unlock
else
m.reply "Help already sent #{@help_time} seconds ago. Wait #{HELP_WAIT_DURATION - @help_time} seconds more."
end
end
def self.exec_version m
m.reply Botpop::VERSION
end
def self.exec_code m
m.reply "https://github.com/pouleta/botpop"
end
def self.exec_help m
help m
end
def self.exec_troll m
# hours = (Time.now.to_i - Time.gm(2015, 04, 27, 9).to_i) / 60 / 60
s = Builtin.get_msg m
url = "http://www.fuck-you-internet.com/delivery.php?text=#{s}"
m.reply url
end
HELP = ["!troll [msg]", "!version", "!code", "!help [plugin]", "!cmds",
"!user ls", "!user <name> group <ls|add|rm> [group]"]
ENABLED = config['enable'].nil? ? true : config['enable']
CONFIG = config
if ENABLED
DB_CONFIG = self.db_config = CONFIG['database']
DB = self.db_connect!
DB.extension :pg_array
require_relative 'base/UserModel'
require_relative 'base/user'
end
def help_wait_before_quit
HELP_WAIT_DURATION.times do
sleep 1
@@help_time += 1
end
end
def help_get_plugins_str
["Plugins found : " + Botpop::PLUGINS.size.to_s] +
Botpop::PLUGINS.map do |plugin|
plugin.to_s.split(':').last
end.compact
end
HELP_WAIT_DURATION = config['help_wait_duration'] || 120
def help m
m.reply help_get_plugins_str.join(', ')
end
def exec_version m
m.reply Botpop::VERSION
end
def exec_code m
m.reply "https://github.com/Nephos/botpop"
end
def exec_help m
help m
end
def exec_help_plugin m
module_name = m.message.split(" ").last.downcase
i = Botpop::PLUGINS.map{|e| e.to_s.split(":").last.downcase}.index(module_name)
if i.nil?
m.reply "No plugin #{module_name}"
return
end
plugin = Botpop::PLUGINS[i]
m.reply plugin::HELP.join(', ')
end
def exec_troll m
# hours = (Time.now.to_i - Time.gm(2015, 04, 27, 9).to_i) / 60 / 60
s = Botpop::Builtins.get_msg m
url = "http://www.fuck-you-internet.com/delivery.php?text=#{s}"
m.reply url
end
end

21
plugins/base/UserModel.rb Normal file
View File

@ -0,0 +1,21 @@
require 'sequel'
class User < Sequel::Model
def is_admin?
self.admin
end
def add_group
end
def del_group
end
def belongs_to? group
self.groups.include? group
end
set_dataset Base::DB[:users]
end

View File

@ -0,0 +1,10 @@
Sequel.migration do
change do
create_table(:users) do
primary_key :id
String :name, null: false, unique: true
TrueClass :admin
column :groups, "text[]"
end
end
end

View File

@ -0,0 +1,11 @@
Sequel.migration do
change do
create_table(:points) do
# primary_key :id
String :assigned_to
String :assigned_by
String :type
DateTime :created_at
end
end
end

View File

@ -0,0 +1,12 @@
Sequel.migration do
change do
create_table(:messages) do
primary_key :id
String :author
String :dest
String :content
DateTime :created_at
DateTime :read_at
end
end
end

View File

@ -0,0 +1,14 @@
Sequel.migration do
change do
create_table(:emails) do
primary_key :id
String :authname
String :address
DateTime :created_at
Integer :usage
Bool :primary, default: false
index [:address], unique: true
end
end
end

View File

@ -0,0 +1,14 @@
Sequel.migration do
change do
create_table(:random_sentences) do
primary_key :id
String :author
String :trigger
String :content
Bool :enabled, default: true
DateTime :created_at
index :trigger, unique: true
end
end
end

View File

@ -0,0 +1,10 @@
Sequel.migration do
change do
create_table(:eips) do
primary_key :id
String :author
String :title
DateTime :created_at
end
end
end

70
plugins/base/user.rb Normal file
View File

@ -0,0 +1,70 @@
class Base
def find_and_exec(m, name)
u = User.where(name: name).first
if u
yield u
else
m.reply "No such user '#{name}'"
end
end
def self.cmd_allowed? m, groups=["admin"], verbose=true
user = User.where(name: m.user.authname).where("groups @> '{#{groups.join(',')}}'").first
if user.nil?
m.reply "No authorized" if verbose
return false
else
return true
end
end
def cmd_allowed? m, groups=["admin"], verbose=true
Base.cmd_allowed?(m, groups, verbose)
end
def user_register m
return m.reply "You are not connected" if m.user.authname.nil?
begin
admin = (User.count == 0)
u = User.create(name: m.user.authname,
admin: admin,
groups: [admin ? 'admin' : 'default'])
m.reply "Welcome ##{u.id} #{u.name}"
rescue => _
m.reply "Cannot register #{m.user.authname}"
end
end
def user_ls m
c = User.count
m.reply User.limit(20).all.map(&:name).join(', ')
if c > 20
m.reply "And #{c-20} more"
end
end
def user_group_ls m, name
cmd_allowed? m
find_and_exec(m, name) do |u|
m.reply u.groups.join(', ')
end
end
def user_group_add m, name, group
cmd_allowed? m
find_and_exec(m, name) do |u|
u.update(groups: (u.groups + [group]))
m.reply "group #{group} added to #{u.name}"
end
end
def user_group_rm m, name, group
cmd_allowed? m
find_and_exec(m, name) do |u|
u.update(groups: (u.groups - [group]))
m.reply "group #{group} removed from #{u.name}"
end
end
end

View File

@ -0,0 +1,68 @@
class CeQueTuDisNAAucunSens < Botpop::Plugin
include Cinch::Plugin
match(/^[^!].+$/, use_prefix: false, method: :say_random_sentence)
match(/^!random_sentence register ([^|]+)\|(.+)/, use_prefix: false, method: :register_trigger)
match(/^!random_sentence remove (.+)/, use_prefix: false, method: :remove_trigger)
HELP = ["!random_sentence register trigger | content",
"!random_sentence remove trigger" ]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def cmd_allowed? m
return Base.cmd_allowed? m, ["random_sentence"]
end
def say_random_sentence m
trigger = I18n.transliterate(m.message).strip
r = Base::DB[:random_sentences].where(enabled: true).where('? ~* "trigger"', trigger).select(:content).first
return if r.nil?
m.reply r[:content].split(' ').shuffle.join(' ')
end
def say_random m
m.reply %w(ce que tu dis n'a aucun sens).shuffle.join(' ')
end
def register_trigger m, t, c
return if not cmd_allowed? m
t = t.triggerize
begin
Base::DB[:random_sentences].insert(trigger: t,
content: c.strip,
author: m.user.authname,
created_at: Time.now.utc)
m.reply "The trigger \"#{t.strip}\" will raise \"#{c.strip}\""
rescue => _err
m.reply "Error. Cannot register this trigger"
m.reply _err
end
end
def remove_trigger m, t
return if not cmd_allowed? m
t = t.triggerize
n = Base::DB[:random_sentences].where(trigger: t).delete
m.reply "Deleted #{n} trigger"
end
end
class String
def triggerize
t = self.dup
t = I18n.transliterate(t).strip
t = Regexp.quote(t)
t.gsub!(/((a)a+)/i, '\2') # ... i know :(
t.gsub!(/((e)e+)/i, '\2')
t.gsub!(/((i)i+)/i, '\2')
t.gsub!(/((o)o+)/i, '\2')
t.gsub!(/((u)u+)/i, '\2')
t.gsub!(/((y)y+)/i, '\2')
t.gsub!(/([aeiouy])/, '\1+')
# TODO: not only " " but also ponctuation etc.
t = "^(.* )?#{t}( .*)?$"
return t
end
end

View File

@ -1,7 +0,0 @@
# This file is independent of /modules_config.yml because it should stay private
creditentials:
username: login
password: pass
organisation: orga
api_url: https://api.pathwar.net/
api_coupon_url: https://api.pathwar.net/organization-coupons/

View File

@ -1,69 +0,0 @@
#encoding: utf-8
require 'uri'
require 'net/http'
require 'json'
module BotpopPlugins
module Coupons
MATCH = lambda do |parent, plugin|
parent.on :message, /coupon(.+)?: .+/ do |m| plugin.exec_coupon m end
end
HELP = ["coupon: [...]"]
CONFIG = Botpop::CONFIG['coupons'] || raise(MissingConfigurationZone, 'coupons')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
SECRET_CONFIG = YAML.load_file('plugins/coupon_login.yml')['creditentials']
USER = SECRET_CONFIG['username']
PASS = SECRET_CONFIG['password']
ORGA = SECRET_CONFIG['organisation']
APIU = SECRET_CONFIG['api_coupon_url']
URL = URI(APIU)
def self.exec_coupon_debug
if @lockcoupon.try_lock
binding.pry rescue return @lockcoupon.unlock
@lockcoupon.unlock
end
end
def self.get_coupon m
coupon = m.params[1..-1].join(' ').gsub(/(coupon(.+)?:)/, '').split.first
coupon = coupon.gsub(/[^A-z0-9\.\-_]/, '') # secure a little
coupon
end
def self.send_coupon coupon
@http ||= Net::HTTP.new(URL.host, URL.port)
@http.use_ssl = true
# http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(URL)
request.add_field('Content-Type', 'application/json')
request.basic_auth USER, PASS
request.body = {'coupon' => coupon, 'organization' => ORGA}.to_json
response = @http.request(request)
@response = response
@request = request
response
end
def self.exec_coupon m
@lockcoupon ||= Mutex.new
coupon = get_coupon m
begin
response = send_coupon coupon
# `curl https://api.pathwar.net/organization-coupons/#{coupon} -u '#{USER}:#{PASS}' -X GET`
if $debug_display_coupons
m.reply "#{coupon} " + (response.code[0] == '2' ? 'validated' : "failed with #{response.code}")
end
rescue => e
m.reply "#{coupon} buggy"
@err = e
exec_coupon_debug if $debug_coupons
end
exec_coupon_debug if $debug_all_coupons
end
end
end

12
plugins/dice/Character.rb Normal file
View File

@ -0,0 +1,12 @@
class Character
attr_accessor :carac, :skills, :hp, :classes, :bab
def initialize(str, dex, con, int, wiz, cha, opt={})
@carac = {str: str, dex: dex, con: con, int: int, wiz: wiz, cha: cha}
@skills = {}
@hp = opt[:hp] || nil
@classes = opt[:classes] || {}
@bab = opt[:bab] || [0]
end
end

98
plugins/dice/Dice.rb Normal file
View File

@ -0,0 +1,98 @@
class FrozenDice
attr_reader :min, :max, :values, :nb, :faces
def initialize arg
if arg.is_a? String
v = arg.match(/^(?<nb>\d+)d(?<faces>\d+)$/i)
if v
set_rolldice v
else
raise ArgumentError unless arg.match(/^\d+$/)
set_value arg.to_i
end
elsif arg.is_a? Integer
set_value arg
else
raise ArgumentError
end
end
def throw
@nb.times.map{ rand(@values) }
end
def test
self.throw.inject(&:+)
end
def mean
v = values.to_a
if v.size % 2 == 0
(v[v.size / 2 - 1] + v[v.size / 2]) * 0.5
else
v[v.size / 2]
end
end
private
def set_rolldice v
@nb, @faces = v[:nb].to_i, v[:faces].to_i
@max = @faces
@min = 1
@values = @min..@max
end
def set_value v
@nb = 1
@faces = v
@min = @faces
@max = @faces
@values = @min..@max
end
end
class Dice
attr_accessor :bonus, :dices
def initialize *arg
@dices = []
arg.each do |a1|
a1.gsub!(" ", "")
a1.split(/[+ ]/).each do |a2|
@dices << FrozenDice.new(a2)
end
end
end
def min
@dices.map do |dice|
dice.min
end
end
def mean
@dices.map do |dice|
dice.mean
end
end
def max
@dices.map do |dice|
dice.max
end
end
def throw
@dices.map do |dice|
dice.throw
end
end
def test
@dices.map do |dice|
dice.test
end.inject(&:+)
end
end

12
plugins/dice/Warrior.rb Normal file
View File

@ -0,0 +1,12 @@
require_relative 'Character'
class Warrior < Character
def initialize str, *arg
super(str, 10, 10, 10, 10, 10, *arg)
end
def str; carac[:str]; end
def bstr; (str - 10) / 2; end
end

84
plugins/dice/Weapon.rb Normal file
View File

@ -0,0 +1,84 @@
require_relative 'Dice'
require_relative 'Warrior'
class Weapon
attr_reader :from, :degats, :opt, :bonus
def initialize from, degats, opt, bonus, attack_opt={}
@from = from
@bonus = from.bab.map{|e| e + bonus}
@degats = Dice.new(degats + "+#{(from.bstr * 1.5).ceil}")
@hands = opt[:hands] || 1
@max = attack_opt[:max] || Float::INFINITY
end
def min
@degats.min
end
def max
@degats.max
end
def mean
@degats.mean
end
def test
@degats.test
end
def mean_p(ca=20.0)
d = @degats.mean.inject(&:+)
p(ca).map do |b|
(b * d).round(4)
end
end
def p(ca=20.0)
@bonus.map do |b|
((b + from.bstr) / ca.to_f).round(4)
end
end
def mean_p_total(ca=20.0)
mean_p(ca).inject(&:+).round(4)
end
def to_s(ca=20)
"mean: #{mean} * #{p(ca)} => #{mean_p(ca)} = #{mean_p_total(ca)}"
end
end
if __FILE__ == $0
alteration = 2
taille = -2
bonus = alteration + taille
epees = []
normal = Warrior.new 18, {bab: [7, 1]}
epees << ["normal", Weapon.new(normal, "4d6+2", {hands: 2}, bonus)]
rage = Warrior.new 19+4, {bab: [7, 1]}
epees << ["rage", Weapon.new(rage, "4d6+2", {hands: 2}, bonus)]
fren = Warrior.new 19+6, {bab: [7, 1]}
epees << ["frenesie", Weapon.new(fren, "4d6+2", {hands: 2}, bonus)]
ra_fr = Warrior.new 19+4+6, {bab: [7, 7, 1]}
epees << ["rage+frenesie", Weapon.new(ra_fr, "4d6+2", {hands: 2}, bonus)]
ra_fr_so = Warrior.new 19+6+4, {bab: [7, 7, 1]}
epees << ["rage+frenesie+sorciere", Weapon.new(ra_fr_so, "4d6+2+5+1d6", {hands: 2}, bonus)]
ra_fr_so_buff = Warrior.new 19+6+4+4, {bab: [7, 7, 1]}
epees << ["rage+frenesie+sorciere+taureau+benediction", Weapon.new(ra_fr_so, "4d6+2+5+1d6", {hands: 2}, bonus+1)]
ra_fr_so_buff_char = Warrior.new 19+6+4+4, {bab: [7, 7]}
epees << ["rage+frenesie+sorciere+taureau+benediction+charge", Weapon.new(ra_fr_so, "4d6+2+5+1d6", {hands: 2}, bonus+1+2, {max: 2})]
epees = Hash[epees]
require 'pry'
binding.pry
end

22
plugins/diceroller.rb Normal file
View File

@ -0,0 +1,22 @@
require_relative 'dice/Dice'
require_relative 'dice/Weapon'
require_relative 'dice/Character'
require_relative 'dice/Warrior'
class Diceroller < Botpop::Plugin
include Cinch::Plugin
match(/!roll (.+)/, use_prefix: false, method: :exec_roll)
HELP = ["!roll (d20 ...)"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
CHARACTER = Warrior.new 10, {bab: [0]}
def exec_roll(m, roll)
val = Weapon.new(CHARACTER, roll, {hands: 1}, 0).test
m.reply "Roll ... '#{roll}' ... #{val}"
end
end

35
plugins/eip.rb Normal file
View File

@ -0,0 +1,35 @@
class Eip < Botpop::Plugin
include Cinch::Plugin
match(/!eip add (.*)/, use_prefix: false, method: :exec_add)
match(/!eip ls/, use_prefix: false, method: :exec_ls)
match(/!eip (\d+)/, use_prefix: false, method: :exec_id)
HELP = ["!eip add ...", "!eip ls", "!eip id"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def exec_add(m, title)
begin
Base::DB[:eips].insert(author: m.user.authname,
title: title,
created_at: Time.now)
m.reply "Ok ! #{title} is a new eip"
rescue
m.reply "Err"
end
end
def exec_id(m, id)
all = Base::DB[:eips].where(id: Integer(id)).first
m.reply all[:title] rescue m.reply("no such id")
end
def exec_ls(m)
all = Base::DB[:eips].limit(3).reverse.all
all.each{|e| m.reply e[:title]}
n = Base::DB[:eips].count
m.reply("There is #{n} elements")
end
end

20
plugins/encrypt.rb Normal file
View File

@ -0,0 +1,20 @@
require 'tor257/core'
require 'base64'
class Encrypt < Botpop::Plugin
include Cinch::Plugin
match(/^!tor257 (c|d) (\w+) (.+)/, use_prefix: false, method: :exec_tor257)
HELP = ["!tor257 <c|d> keyphrase data"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def exec_tor257 m, type, k, d
d = Base64.decode64(d.strip) if type == 'd'
e = Tor257::Message.new(d).encrypt(Tor257::Key.new(k)).to_s
e = Base64.encode64(e) if type == 'c'
m.reply e
end
end

View File

@ -1,18 +1,14 @@
#encoding: utf-8
class MyFury < Botpop::Plugin
include Cinch::Plugin
module BotpopPlugins
module MyFuryPlugin
match(/!whatkingofanimal.*/, use_prefix: false, method: :exec_whatkingofanimal)
MATCH = lambda do |parent|
parent.on :message, /!whatkingofanimal.*/ do |m| BotpopPlugins::exec_whatkingofanimal m end
end
HELP = ["!whatkingofanimal", "!animallist", "!checkanimal [type]"]
CONFIG = Botpop::CONFIG['example'] || raise(MissingConfigurationZone, 'example')
ENABLED = CONFIG['enable'].nil? ? false : CONFIG['enable']
def self.exec_whatkingofanimal m
m.reply "Die you son of a" + ["lion", "pig", "red panda"].shuffle.first + " !!"
end
HELP = ["!whatkingofanimal", "!animallist", "!checkanimal [type]"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def exec_whatkingofanimal m
m.reply "Die you son of a" + ["lion", "pig", "red panda"].sample + " !!"
end
end

View File

@ -1,65 +1,111 @@
# encoding: utf-8
class IAmAlive < Botpop::Plugin
include Cinch::Plugin
include Botpop::Plugin::Database
# 4.times {puts "=".yellow * 74}
# puts "THE IAMALIVE PLUGINS IN INSANE. DISABLE BY USING --plugin-disable iamalive".red
# 4.times {puts "=".yellow * 74}
# sleep 1
match(/^[^!].*/, use_prefix: false, method: :register_entry)
match(/^[^!].*/, use_prefix: false, method: :react_on_entry)
match(/^!iaa reac(tivity)?$/, use_prefix: false, method: :get_reactivity)
match(/^!iaa reac(tivity)? \d{1,3}$/, use_prefix: false, method: :set_reactivity)
match(/^!iaa learn$/, use_prefix: false, method: :set_mode_learn)
match(/^!iaa live$/, use_prefix: false, method: :set_mode_live)
match(/^!iaa mode$/, use_prefix: false, method: :get_mode)
match(/^!iaa stats?$/, use_prefix: false, method: :get_stats)
match(/^!iaa forget( (\d+ )?(.+))?/, use_prefix: false, method: :forget)
match(/^!iaa last( \w+)?$/, use_prefix: false, method: :get_last)
module BotpopPlugins
module IAmAlive
CONFIG = config(:safe => true)
ENABLED = CONFIG['enable'] || false
HELP = ["!iaa reac", "!iaa reac P", "!iaa learn", "!iaa live", "!iaa mode",
"!iaa stats", "!iaa forget (Nx SENTENCE)", "!iaa last (nick)",
"!iaa user [add/remove/list]"]
MATCH = lambda do |parent, plugin|
parent.on :message, /.+/ do |m| plugin.exec_learn m end
parent.on :message, /.+/ do |m| plugin.exec_speak m end
parent.on :message, "!iaa clean" do |m| plugin.exec_clean m end
end
HELP = ["I'm learning from you"]
CONFIG = Botpop::CONFIG['iamalive'] || raise(MissingConfigurationZone, 'iamalive')
DATABASE_FILE = CONFIG['database_file'] || raise(MissingConfigurationEntry, 'iamalive::database_file')
File.open(DATABASE_FILE, 'r') rescue init_database
# DISABLED MAY BE CONFIGURED, DEFAULT IS TRUE
ENABLED = CONFIG['enable'].nil? ? false : CONFIG['enable']
def self.init_database
f = File.open(DATABASE_FILE, 'w')
f.write("learn:\n")
f.close
end
def self.open_database
begin
@iamalive_db = YAML.load_file(DATABASE_FILE)['learn'].to_a
rescue
init_database
retry
end
end
# Store in a database
def self.exec_learn m
line = m.params[1..-1].join(' ').to_yaml.gsub("--", " ").gsub("...\n", "")
return if line.include?("VERSION") or line.match /\A["']?!/ or line.match(/\Ahttp/)
f = File.open(DATABASE_FILE, 'a')
f.write(line)
f.close
# m.reply "Learn: #{line}"
end
PROBA = 6
def self.exec_speak m
if Random.rand(PROBA).zero?
open_database
i = Random.rand(@iamalive_db.size)
m.reply @iamalive_db[i]
else
# m.reply "no reply"
end
end
def self.exec_clean m
init_database
end
@@mode = config['default_mode'].to_sym
@@reactivity = config['reactivity'] || 50
def cmd_allowed? m
return Base.cmd_allowed? m, ["iaa"]
end
if ENABLED
DB_CONFIG = self.db_config = CONFIG['database']
DB = self.db_connect!
require_relative 'iamalive/entry'
end
def register_entry m
Entry.create(user: (m.user.authname || m.user.nick), message: m.message, channel: m.channel.to_s)
forget_older! if rand(1..100) == 100
end
def react_on_entry m
return if @@mode != :live
e = Entry.where('LOWER(message) = LOWER(?)', m.message).select(:id).all.map(&:id).map{|x| x+1}
if @@reactivity > rand(1..100)
answer_to(m, e)
end
end
private
def answer_to m, e
a = Entry.where(id: e).to_a.sample
if not a.nil?
sleep(a.message.split.size.to_f / 10)
m.reply a.message
Entry.create(user: "self", message: a.message, channel: m.channel.to_s)
end
end
def forget_older!
log "Forget the older entry"
Entry.first.delete
end
public
def get_reactivity m
m.reply "Current reactivity: #{@@reactivity}"
end
def set_reactivity m
return if not cmd_allowed? m
@@reactivity = m.message.split[2].to_i
end
def set_mode_learn m
return if not cmd_allowed? m
@@mode = :learn
end
def set_mode_live m
return if not cmd_allowed? m
@@mode = :live
end
def get_mode m
m.reply "Current mode: #{@@mode}"
end
def get_stats m
m.reply "Registered sentences: #{Entry.count}"
end
def forget m, arguments, nb, what
return if not cmd_allowed? m
if arguments.nil?
last = Entry.where(channel: m.channel.to_s, user: "self").last
m.reply last ? "\"#{last.message}\" Forgotten" : "Nop"
last.delete
else
nb = nb.to_i if not nb.nil?
nb ||= Entry.where(message: what).count
n = Entry.where(message: what).order_by(:id).reverse.limit(nb).map(&:delete).size rescue 0
m.reply "(#{n}x) \"#{what}\" Forgotten"
end
end
def get_last m, user
user.strip! if user
last = Entry.where(channel: m.channel.to_s, user: (user || "self")).last
m.reply "#{user}: #{last ? last.message : 'no message found'}"
end
end

View File

@ -0,0 +1,29 @@
# I Am Alive
I am alive is a plugin, that allows to bot to answer to me :)
## Initialization
### Database
Firstly, create the database and migrate it. To do this, use the following command.
In the ``modules_config.yml`` file, configure it for your engine.
As it use sequel engine, it is compatible with sqlite, mysql, postgres, etc.
Checkout the [sequel documentaiton](http://sequel.jeremyevans.net/documentation.html) for more informations.
Then, execute one of two:
```bash
sequel -m plugins/iamalive/migrations sqlite://plugins/iamalive/db.sqlite3
sequel -m plugins/iamalive/migrations postgres://root:toor@localhost:5432/botpop_iamalive
...
```
You can change the name of the database via the global configuration file (see the example).
### User / Admin
Only authorized users have the rights to administrate the iaa plugin.
Only when there is no administrator (by default), you can use the command "!iaa user add NICK" to add your NICK to the database.
Be sure you have a protected identity.
Then, only administrators can add / remove admin from the list.

View File

@ -0,0 +1,9 @@
require 'sequel'
class IAmAlive
class Admin < Sequel::Model
set_dataset DB[:admins]
end
end

31
plugins/iamalive/entry.rb Normal file
View File

@ -0,0 +1,31 @@
require 'sequel'
class IAmAlive
class IAAMessage < String
def initialize *arg
super(*arg)
self.strip!
end
end
class Entry < Sequel::Model
def before_create
self.created_at ||= Time.now
self.message.strip!
self.message_origin = self.message
self.message = IAAMessage.new(self.message).to_s
super
end
set_dataset DB[:entries]
def self.anwser(message)
Entry.where('LOWER(message) = LOWER(?)', m.message.to_iaa_message).
select(:id).all.map(&:id).map{|x| x+1}
end
end
end

View File

@ -0,0 +1,12 @@
Sequel.migration do
change do
create_table(:entries) do
primary_key :id
String :user, null: false
String :channel, null: false
String :message, null: false, text: true
String :message_origin, null: false, text: true
DateTime :created_at
end
end
end

View File

@ -0,0 +1,8 @@
Sequel.migration do
change do
create_table(:admins) do
primary_key :id
String :user, null: false
end
end
end

View File

@ -1,41 +0,0 @@
#encoding: utf-8
module BotpopPlugins
module Intranet
MATCH = lambda do |parent, plugin|
parent.on :message, "!intra" do |m| plugin.exec_intra m end
parent.on :message, "!intra on" do |m| plugin.exec_intra_on m end
parent.on :message, "!intra off" do |m| plugin.exec_intra_off m end
end
HELP = ["!intra <on, off>"]
CONFIG = Botpop::CONFIG['intranet'] || raise(MissingConfigurationZone, 'intranet')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
def self.exec_intra m
m.reply Builtin.intra_state rescue m.reply "I'm buggy. Sorry"
end
INTRA_PING_SLEEP = 30
def self.exec_intra_on m
@intra ||= Mutex.new
if @intra.try_lock
@intra_on = true
m.reply "INTRANET SPY ON"
while @intra_on
m.reply Builtin.intra_state rescue return @intra.unlock
sleep INTRA_PING_SLEEP
end
@intra.unlock
else
m.reply "INTRA SPY ALREADY ON"
end
end
def self.exec_intra_off m
m.reply @intra_on ? "INTRA SPY OFF" : "INTRA SPY ALREADY OFF"
@intra_on = false
end
end
end

27
plugins/kick.rb Normal file
View File

@ -0,0 +1,27 @@
#encoding: utf-8
class Kick < Botpop::Plugin
include Cinch::Plugin
match(/!k (.+)/, use_prefix: false, method: :exec_kick)
match(/!kick (.+)/, use_prefix: false, method: :exec_kick)
match(/!k ([^|]+)\|(.+)/, use_prefix: false, method: :exec_kick_message)
match(/!kick ([^|]+)\|(.+)/, use_prefix: false, method: :exec_kick_message)
HELP = ["!kick nickname <message>"]
ENABLED = config['enable'].nil? ? true : config['enable']
CONFIG = config
def exec_kick m, victim
len = CONFIG["list"].length - 1
msg = CONFIG["list"][rand(0..len)]
m.channel.kick(victim, msg)
m.reply "Bye bye " + victim
end
def exec_kick_message m, victim, reason
m.channel.kick(victim, reason)
m.reply "Bye bye " + victim
end
end

68
plugins/log.rb Normal file
View File

@ -0,0 +1,68 @@
#encoding: utf-8
class Log < Botpop::Plugin
include Cinch::Plugin
match /users$/, use_prefix: true, method: :exec_list_user
match /remove .+$/, use_prefix: true, method: :exec_remove_user
match /add .+$/, use_prefix: true, method: :exec_add_user
match /clean$/, use_prefix: true, method: :exec_clean
match /status$/, use_prefix: true, method: :exec_status
match /enable$/, use_prefix: true, method: :exec_log_enable
match /.+/, use_prefix: false, method: :exec_log
HELP = ["!log enable", "!log add", "!log remove", "!log users", "!log clean", "!log status"]
CONFIG = config
ENABLED = CONFIG['enable'].nil? ? false : CONFIG['enable']
USER_CONFIG = "plugins/log_user.yml"
USERS = YAML.load_file(USER_CONFIG) || raise(MissingConfigurationZone, USER_CONFIG)
@@log_user_list = USERS["list"]
@@log_enabled = CONFIG["default_started"]
def exec_list_user m
m.reply @@log_user_list.join(", ")
m.reply "no log admin" if @@log_user_list.empty?
end
def exec_remove_user m
return unless is_admin? m
m.message.gsub("!log add ", "").split(" ").each do |name|
@@log_user_list.delete name unless USERS["list"].include?(name)
end
end
def exec_add_user m
return unless is_admin? m
@@log_user_list += m.message.gsub("!log add ", "").split(" ")
@@log_user_list.uniq!
end
def exec_log_enable m
@@log_enabled = !@@log_enabled
exec_status m
end
def exec_status m
m.reply "Log #{@@log_enabled ? :enabled : :disabled}"
end
def exec_clean m
return unless is_admin? m
File.delete(CONFIG["file"]) rescue nil
end
def exec_log m
log(m) if @@log_enabled
end
private
def log m
File.open(CONFIG["file"], 'a') {|f| f << (m.user.to_s + ": " + m.message + "\n")}
end
def is_admin? m
@@log_user_list.include? m.user.to_s
end
end

View File

@ -0,0 +1,2 @@
list:
- poulet_a

View File

@ -1,160 +1,175 @@
#encoding: utf-8
module BotpopPlugins
module Network
class Network < Botpop::Plugin
include Cinch::Plugin
MATCH = lambda do |parent, plugin|
parent.on :message, "!ping" do |m| plugin.exec_ping m end
parent.on :message, /!ping #{Botpop::TARGET}\Z/ do |m| plugin.exec_ping_target m end
parent.on :message, /!httping #{Botpop::TARGET}\Z/ do |m| plugin.exec_ping_http m end
parent.on :message, /!dos #{Botpop::TARGET}\Z/ do |m| plugin.exec_dos m end
parent.on :message, /!fok #{Botpop::TARGET}\Z/ do |m| plugin.exec_fok m end
parent.on :message, /!trace #{Botpop::TARGET}\Z/ do |m| plugin.exec_trace m end
parent.on :message, /!poke #{Botpop::TARGET}\Z/ do |m| plugin.exec_poke m end
end
match("!ping", use_prefix: false, method: :exec_ping)
match(/!ping #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_ping_target)
match(/!httping #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_ping_http)
match(/!dos #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_dos)
match(/!fok #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_fok)
match(/!trace #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_trace)
match(/!poke #{Botpop::TARGET}\Z/, use_prefix: false, method: :exec_poke)
HELP = ["!ping", "!ping [ip]", "!httping [ip]",
"!dos [ip]", "!fok [nick]", "!trace [ip]", "!poke [nick]"]
CONFIG = Botpop::CONFIG['network'] || raise(MissingConfigurationZone, 'network')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
# @param what [Net::Ping::External]
# @param what [Net::Ping::HTTP]
def self.ping_with m, what
ip = Builtin.get_ip m
p = what.new ip
str = p.ping(ip) ? "#{(p.duration*100.0).round 2}ms (#{p.host})" : 'failed'
m.reply "#{ip} > #{what.to_s.split(':').last} ping > #{str}"
end
def self.exec_ping m
m.reply "#{m.user} > pong"
end
def self.exec_ping_target m
ping_with m, Net::Ping::External
end
def self.exec_ping_http m
ping_with m, Net::Ping::HTTP
end
def self.exec_poke m
nick = Builtin.get_ip_from_nick(m)[:nick]
ip = Builtin.get_ip_from_nick(m)[:ip]
return m.reply "User '#{nick}' doesn't exists" if ip.nil?
# Display
response = Builtin.ping(ip) ? "#{(p.duration*100.0).round 2}ms (#{p.host})" : "failed"
m.reply "#{nick} > poke > #{response}"
end
DOS_DURATION = "2s"
def self.dos_get_duration
Botpop::CONFIG['network']['duration'] || DOS_DURATION rescue DOS_DURATION
end
DOS_WAIT = '5s'
def self.dos_get_wait
wait = Botpop::CONFIG['network']['wait'] || DOS_DURATION rescue DOS_DURATION
return wait.to_i / 100.0 if wait.match /\d+ms\Z/
return wait.to_i
end
def self.dos_check_ip(m, ip)
return true if Builtin.ping(ip)
m.reply "Cannot reach the host '#{ip}'"
return false
end
def self.dos_replier m, ip, s
if s.nil?
m.reply "The dos has failed"
elsif Builtin.ping(ip)
m.reply "Sorry, the target is still up ! --- #{s}"
else
m.reply "Target down ! --- #{s}"
end
end
# This function avoid overusage of the resources by using mutex locking.
# It execute the lamdba function passed as 2sd parameter if resources are ok
# At the end of the attack, it wait few seconds (configuration) before
# releasing the resources and permit a new attack.
#
# @arg lambda [Lambda] lambda with one argument (m). It wil be executed
def self.dos_execution(m, lambda)
@dos ||= Mutex.new
if @dos.try_lock
lambda.call(m)
sleep dos_get_wait
@dos.unlock
else
m.reply "Wait for the end of the last dos"
end
end
def self.exec_dos m
dos_execution m, lambda {|m|
ip = Builtin.get_ip m
return if not dos_check_ip(m, ip)
m.reply "Begin attack against #{ip}"
s = Builtin.dos(ip, dos_get_duration).split("\n")[3].to_s rescue nil
dos_replier m, ip, s
}
end
def self.exec_fok m
dos_execution m, lambda {|m|
nick = Builtin.get_ip_from_nick(m)[:nick]
ip = Builtin.get_ip_from_nick(m)[:ip]
return m.reply "User '#{nick}' doesn't exists" if ip.nil?
return m.reply "Cannot reach the host '#{ip}'" if not Builtin.ping(ip)
s = Builtin.dos(ip, dos_get_duration).split("\n")[3].to_s
m.reply "#{nick} : " + (Builtin.ping(ip) ? "failed :(" : "down !!!") + " " + s
}
end
# Trace is complexe. 3 functions used exec_trace_display_lines, exec_trace_with_time, exec_trace
TRACE_DURATION_INIT = 0.3
TRACE_DURATION_INCR = 0.1
def self.trace_display_lines m, lines
lines.select!{|e| not e.include? "no reply" and e =~ /\A \d+: .+/}
duration = TRACE_DURATION_INIT
lines.each do |l|
m.reply l
sleep duration
duration += TRACE_DURATION_INCR
end
m.reply 'finished'
end
def self.trace_with_time ip
t1 = Time.now
s = Builtin.trace ip
t2 = Time.now
return [s, t1, t2]
end
def self.exec_trace m
@trace ||= Mutex.new
if @trace.try_lock
ip = Builtin.get_ip m
m.reply "It can take time"
begin
# Calculations
s, t1, t2 = trace_with_time ip
m.reply "Trace executed in #{(t2 - t1).round(3)} seconds"
@trace.unlock
rescue => e
m.reply "Sorry, but the last author of this plugin is so stupid his mother is a tomato"
@trace.unlock
end
# Display
trace_display_lines m, s
else
m.reply "Please retry after when the last trace end"
end
end
HELP = ["!ping", "!ping [ip]", "!httping [ip]",
"!dos [ip]", "!fok [nick]", "!trace [ip]", "!poke [nick]"]
ENABLED = config['enable'].nil? ? true : config['enable']
CONFIG = config
private
# Conversion of the string to value in ms
def self.config_string_to_time(value)
value.match(/\d+ms\Z/) ? value.to_f / 100.0 : value.to_f
end
public
DOS_DURATION = config['dos_duration'] || '2s'
DOS_WAIT_DURATION_STRING = config['dos_wait'] || '5s'
DOS_WAIT_DURATION = config_string_to_time DOS_WAIT_DURATION_STRING
# Trace is complexe. 3 functions used exec_trace_display_lines, exec_trace_with_time, exec_trace
TRACE_DURATION_INIT_STRING_DEFAULT = "0.3s"
TRACE_DURATION_INIT_STRING = config['trace_duration_init'] || TRACE_DURATION_INIT_STRING_DEFAULT
TRACE_DURATION_INCR_STRING_DEFAULT = "0.1s"
TRACE_DURATION_INCR_STRING = config['trace_duration_incr'] || TRACE_DURATION_INCR_STRING_DEFAULT
TRACE_DURATION_INIT = config_string_to_time TRACE_DURATION_INIT_STRING
TRACE_DURATION_INCR = config_string_to_time TRACE_DURATION_INCR_STRING
# @param what [Net::Ping::External]
# @param what [Net::Ping::HTTP]
def ping_with m, what
ip = Botpop::Builtins.get_ip m
p = what.new ip
str = p.ping(ip) ? "#{(p.duration*100.0).round 2}ms (#{p.host})" : 'failed'
m.reply "#{ip} > #{what.to_s.split(':').last} ping > #{str}"
end
def exec_ping m
m.reply "#{m.user} > pong"
end
def exec_ping_target m
ping_with m, Net::Ping::External
end
def exec_ping_http m
ping_with m, Net::Ping::HTTP
end
def exec_poke m
nick = Botpop::Builtins.get_ip_from_nick(m)[:nick]
ip = Botpop::Builtins.get_ip_from_nick(m)[:ip]
return m.reply "User '#{nick}' doesn't exists" if ip.nil?
# Display
response = Botpop::Builtins.ping(ip) ? "#{(p.duration*100.0).round 2}ms (#{p.host})" : "failed"
m.reply "#{nick} > poke > #{response}"
end
def dos_check_ip(m, ip)
return true if Botpop::Builtins.ping(ip)
m.reply "Cannot reach the host '#{ip}'"
return false
end
def dos_replier m, ip, s
if s.nil?
m.reply "The dos has failed"
elsif Botpop::Builtins.ping(ip)
m.reply "Sorry, the target is still up !"
else
m.reply "Target down ! --- #{s}"
end
end
# This function avoid overusage of the resources by using mutex locking.
# It execute the lamdba function passed as 2sd parameter if resources are ok
# At the end of the attack, it wait few seconds (configuration) before
# releasing the resources and permit a new attack.
#
# @arg lambda [Lambda] lambda with one argument (m). It wil be executed
def dos_execution(m, lambda)
@dos ||= Mutex.new
if @dos.try_lock
lambda.call(m)
sleep DOS_WAIT_DURATION
@dos.unlock
else
m.reply "Wait for the end of the last dos"
end
end
def dos_ip(ip)
return Botpop::Builtins.dos(ip, DOS_DURATION).split("\n")[3].to_s rescue nil
end
def exec_dos m
dos_execution m, lambda {|m|
ip = Botpop::Builtins.get_ip m
return if not dos_check_ip(m, ip)
m.reply "Begin attack against #{ip}"
s = dos_ip(ip)
dos_replier m, ip, s
}
end
def exec_fok m
dos_execution m, lambda {|m|
nick = Botpop::Builtins.get_ip_from_nick(m)[:nick]
ip = Botpop::Builtins.get_ip_from_nick(m)[:ip]
return m.reply "User '#{nick}' doesn't exists" if ip.nil?
return m.reply "Cannot reach the host '#{ip}'" if not Botpop::Builtins.ping(ip)
s = dos_ip(ip)
r = Botpop::Builtins.ping(ip) ? "failed :(" : "down !!!"
m.reply "#{nick} : #{r} #{s}"
}
end
def trace_display_lines m, lines
lines.select!{|e| not e.include? "no reply" and e =~ /\A \d+: .+/}
duration = TRACE_DURATION_INIT
lines.each do |l|
m.reply l
sleep duration
duration += TRACE_DURATION_INCR
end
m.reply 'finished'
end
def trace_with_time ip
t1 = Time.now
s = Botpop::Builtins.trace ip
t2 = Time.now
return [s, t1, t2]
end
# see {trace_execution}. Seem system without sleep
#
# @arg lambda [Lambda] lambda with one argument (m). It wil be executed
def trace_execution(m, lambda)
@trace ||= Mutex.new
if @trace.try_lock
lambda.call(m) rescue nil
@trace.unlock
else
m.reply "A trace is still running"
end
end
def exec_trace m
trace_execution m, lambda {|m|
ip = Botpop::Builtins.get_ip m
m.reply "It can take time"
begin
# Calculations
s, t1, t2 = trace_with_time ip
m.reply "Trace executed in #{(t2 - t1).round(3)} seconds"
rescue => e
m.reply "Sorry, but the last author of this plugin is so stupid his mother is a tomato"
end
# Display
trace_display_lines m, s
}
end
end

51
plugins/ops.rb Normal file
View File

@ -0,0 +1,51 @@
#encoding: utf-8
class Ops < Botpop::Plugin
include Cinch::Plugin
match(/!op/, use_prefix: false, method: :exec_op)
match(/!op (.+)/, use_prefix: false, method: :exec_op_other)
match(/!deop/, use_prefix: false, method: :exec_deop)
match(/!deop (.+)/, use_prefix: false, method: :exec_deop_other)
match(/!v/, use_prefix: false, method: :exec_voice)
match(/!v (.+)/, use_prefix: false, method: :exec_voice_other)
match(/!dv/, use_prefix: false, method: :exec_devoice)
match(/!dv (.+)/, use_prefix: false, method: :exec_devoice_other)
HELP = ["!op <nickname>", "!deop <nickname>"]
ENABLED = config['enable'].nil? ? true : config['enable']
CONFIG = config
def exec_op m
m.channel.op(m.user)
end
def exec_op_other m, other
m.channel.op(other)
end
def exec_deop m
m.channel.deop(m.user)
end
def exec_deop_other m, other
m.channel.deop(other)
end
def exec_voice m
m.channel.voice(m.user)
end
def exec_voice_other m, other
m.channel.voice(other)
end
def exec_devoice m
m.channel.devoice(m.user)
end
def exec_devoice_other m, other
m.channel.devoice(other)
end
end

17
plugins/poilo.rb Normal file
View File

@ -0,0 +1,17 @@
# coding: utf-8
class Poilo < Botpop::Plugin
include Cinch::Plugin
match(/^[^!].+/, use_prefix: false, method: :exec_poilo)
ENABLED = config['enable'].nil? ? false : config['enable']
SYLLABE = %w(a i o u y oi eau au ou an eu)
CONFIG = config
def exec_poilo m
word = m.message.split.last
syl = word.split(/[^aeiouy]/).last
m.reply "poil au " + CONFIG["list"][syl] if not syl.nil?
end
end

76
plugins/points.rb Normal file
View File

@ -0,0 +1,76 @@
#encoding: utf-8
class Points < Botpop::Plugin
include Cinch::Plugin
include Botpop::Plugin::Database
match(/.*/, use_prefix: false, method: :save_last_user)
match(/^!pstats?$/, use_prefix: false, method: :statistics)
match(/^!pstats?u (\w+)$/, use_prefix: false, method: :statistics_for_user)
match(/^!pstats?p (\w+)$/, use_prefix: false, method: :statistics_for_point)
match(/^!p +(\w+)$/, use_prefix: false, method: :add_point_to_last)
match(/^!p +(\w+) +(\w+)$/, use_prefix: false, method: :add_point_to_user)
match(/hei(l|i)/i, use_prefix: false, method: :point_nazi)
HELP = ["!p <type> [to]", "!pstats", "!pstatsu <nick>", "!pstatsp <point>"]
ENABLED = config['enable'].nil? ? true : config['enable']
CONFIG = config
@@users = {}
@@lock = Mutex.new
def statistics m
ret = Base::DB.fetch("SELECT points.type, COUNT(*) AS nb FROM points GROUP BY points.type ORDER BY nb DESC LIMIT 10;").all.map{|e| e[:type] + "(#{e[:nb]})"}.join(", ")
# data = Base::DB.fetch("SELECT points.type, COUNT(points.*) AS nb FROM points GROUP BY points.type ORDER BY nb DESC LIMIT 10;").all
# data.map!{|e| Base::DB.fetch("SELECT assigned_to FROM points GROUP BY type, assigned_to HAVING type = ? ORDER BY COUNT(*) DESC;", e[:type]).first.merge(e)}
# ret = data.map{|e| e[:type] + "(#{e[:nb]}x #{e[:assigned_to]})"}.join(", ")
m.reply "Top used: #{ret}"
end
def statistics_for_user m, u
ret = Base::DB.fetch("SELECT points.type, COUNT(*) AS nb FROM points WHERE assigned_to = ? GROUP BY points.type ORDER BY COUNT(*) DESC LIMIT 10;", u.downcase).all.map{|e| e[:type] + "(#{e[:nb]})"}.join(", ")
m.reply "User #{u} has: #{ret}"
end
def statistics_for_point m, p
data = Base::DB.fetch("SELECT assigned_to, COUNT(*) AS nb FROM points GROUP BY type, assigned_to HAVING type = ? ORDER BY COUNT(*) DESC LIMIT 10;", p).all
ret = data.map{|e| e[:assigned_to] + "(#{e[:nb]})"}.join(", ")
m.reply "Point #{p}: #{ret}"
end
def save_last_user m
return if m.message.match(/^!p .+$/)
@@lock.lock
@@users[m.channel.to_s] = m.user.nick
@@lock.unlock
end
def add_point_to_last m, type
return if @@users[m.channel.to_s].nil?
nick = @@users[m.channel.to_s]
count = add_point(m.user.nick, nick, type)
m.reply "#{nick} has now #{count} points #{type} !"
end
def add_point_to_user m, type, nick
count = add_point(m.user.nick, nick, type)
m.reply "#{nick} has now #{count} points #{type} !"
end
def point_nazi m
nick = m.user.nick
count = add_point("self", nick, "nazi")
m.reply "#{nick} has now #{count} points nazi !" if count % 10 == 0
end
private
def add_point(by, to, type)
to.downcase!
Base::DB[:points].insert({assigned_by: by,
assigned_to: to,
type: type,
created_at: Time.now})
Base::DB[:points].where(assigned_to: to, type: type).count
end
end

View File

@ -0,0 +1,12 @@
require 'sequel'
class Point < Sequel::Model
def before_save
return false if super == false
self.created_at = Time.now
end
set_dataset Base::DB[:points]
end

1
plugins/points/migrations Symbolic link
View File

@ -0,0 +1 @@
base/migrations/

123
plugins/proxy.rb Normal file
View File

@ -0,0 +1,123 @@
#encoding: utf-8
trap('SIGINT') {
Botpop::Plugins::Proxy.database_users_write({})
exit
}
class Proxy < Botpop::Plugin
include Cinch::Plugin
match("!proxy list", use_prefix: false, method: :exec_proxy_list)
match("!proxy ip", use_prefix: false, method: :exec_proxy_ip)
match("!proxy get", use_prefix: false, method: :exec_proxy_get)
match("!proxy drop", use_prefix: false, method: :exec_proxy_drop)
HELP = ["!proxy list", "!proxy ip", "!proxy get", "!proxy drop"]
ENABLED = config['enable'].nil? ? true : config['enable']
if ENABLED
require 'htauth'
require 'digest'
end
LIMIT_USERS = config['limit_users'] || 1
PASSWD_FILE = config['passwd_file'] || '/etc/squid3/passwords'
IP = config['ip_addr'] || raise(MissingConfigurationEntry, 'ip_addr')
PORT = config['ip_port'] || raise(MissingConfigurationEntry, 'ip_port')
File.open(PASSWD_FILE, 'a') {}
LOCKED_USERS = File.readlines(PASSWD_FILE)
@@proxy_users = []
def username m
Digest::SHA256.hexdigest m.user.nick
end
def password_rand
File.readlines('/proc/sys/kernel/random/uuid').first.split('-').last.chomp
end
def database_users_reset
File.write(PASSWD_FILE, '')
end
def database_users_read
begin
return File.readlines(PASSWD_FILE)
rescue
database_users_reset
sleep 1
retry
end
end
def database_users_write users
database_users_reset
contents = (LOCKED_USERS + users.map{|u,p| "#{u}:#{p}"}).join("\n").chomp
contents += "\n" if not contents.empty?
File.write(PASSWD_FILE, contents)
end
def users
users = database_users_read
users.map!{|l| l.chomp.split(':')}
users.map!{|u| {u[0] => u[1]}}
users = users.reduce({}) {|h,pairs| pairs.each {|k,v| h[k] = v}; h}
users
end
def remove_user nick
users = database_users_read
users.delete_if {|line| line =~ /\A#{nick}:.+/ }
database_users_write users
end
def add_user username, password
p = HTAuth::PasswdFile.new(PASSWD_FILE)
p.add(username, password)
p.save!
end
def user_exists? m
users[username m]
end
def exec_proxy_list m
users.keys.each_with_index do |username, i|
m.reply "Proxy list [#{i+1}/#{users.size}/#{LIMIT_USERS}] : #{username}"
sleep 0.1
end
end
def exec_proxy_ip m
m.reply "Proxy connexion on http://#{IP}:#{PORT}"
end
def exec_proxy_get m
if not user_exists? m
password = password_rand
@@proxy_users << m.user.nick
add_user(username(m), password)
m.reply "User : #{username(m)} created, password : #{password}"
else
if @@proxy_users.include? m.user.nick
m.reply "You already have a proxy. Drop it before creating a new one."
else
m.reply "Locked nick #{m.user.nick} out of the my jurisdiction. Use an other."
end
end
end
def exec_proxy_drop m
if @@proxy_users.include?(m.user.nick) and user_exists? m
@@proxy_users.delete(m.user.nick)
remove_user(username(m))
m.reply "Removed."
else
m.reply "No proxy registered with your nick on my jurisdiction."
end
end
end

119
plugins/puppet.rb Normal file
View File

@ -0,0 +1,119 @@
require 'date'
class Puppet < Botpop::Plugin
include Cinch::Plugin
match(/^!pm (\#*\w+) (.*)/, use_prefix: false, method: :send_privmsg)
match(/^!join (\#\w+)/, use_prefix: false, method: :join)
match(/^!part (\#\w+)/, use_prefix: false, method: :part)
# Email handlement
EMAIL = '[[:alnum:]\.\-_]{1,64}@[[:alnum:]\.\-_]{1,64}'
NICK = '\w+'
# Registration of an email address - association with authname
match(/^!mail register (#{EMAIL})$/, use_prefix: false, method: :register)
match(/^!mail primary (#{EMAIL})$/, use_prefix: false, method: :make_primary)
# Send email to user through its nickname (not safe)
match(/^!(mail )?(let|send) (#{NICK}) (.+)/, use_prefix: false, method: :let)
# Send email to user through one of its emails (safe)
match(/^!(mail )?(let|send) (#{EMAIL}) (.+)/, use_prefix: false, method: :let)
# Read email (based on nickname, authname, and emails)
match(/^!(mail )?r(ead)?$/, use_prefix: false, method: :read)
HELP = ["!pm <#chat/nick> <message>", "!join <#chan>", "!part <#chan>", "!let <to> msg", "!read"] +
["!mail read", "!mail send/let <...>", "!mail register address"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def send_privmsg m, what, message
if what.match(/^\#.+/)
send_privmsg_to_channel(what, message)
else
send_privmsg_to_user(what, message)
end
end
def join m, chan
Channel(chan).join
end
def part m, chan
Channel(chan).part
end
def register m, email
begin
Base::DB[:emails].insert(authname: m.user.authname,
address: email,
created_at: Time.now.utc,
usage: 0)
rescue => _
return m.reply "Error, cannot register this email !"
end
return m.reply "Email #{email} registered for you, #{m.user.authname}"
end
def make_primary m, email
a = get_addresses(m.user).where(address: email)
return m.reply "No your email #{email}" if a.first.nil?
get_addresses(m.user).update(primary: false)
a.update(primary: true)
m.reply "Your primary email #{m.user.nick} is now #{email}"
end
def let m, _, _, to, msg
log "New message addressed to #{to} to send"
# insert new message in database
from = Base::DB[:emails].where(authname: m.user.authname, primary: true).select(:address).first
from = from && from[:address] || m.user.nick
Base::DB[:messages].insert(author: from,
dest: to,
content: msg.strip,
created_at: Time.now,
read_at: nil)
Base::DB[:emails].where(address: to).update('usage = usage+1')
end
def read m, _
msg = get_messages(m.user).first
if msg.nil?
send_privmsg_to_user m.user, "No message."
return
end
Base::DB[:messages].where(id: msg[:id]).update(read_at: Time.now)
date = msg[:created_at]
if Date.parse(Time.now.to_s) == Date.parse(date.to_s)
date = date.strftime("%H:%M:%S")
else
date = date.strftime("%B, %d at %H:%M:%S")
end
send_privmsg_to_user m.user, "##{msg[:id]}# #{date} -- from #{msg[:author]}"
send_privmsg_to_user m.user, msg[:content]
end
listen_to :join, method: :bip_on_join
def bip_on_join m
nb = Base::DB[:messages].where(dest: m.user.nick, read_at: nil).count
send_privmsg_to_user m.user, "#{m.user.nick}: You have #{nb} message unread." unless nb.zero?
end
private
def send_privmsg_to_channel chan, msg
Channel(chan).send(msg.strip)
end
def send_privmsg_to_user user, msg
User(user).send(msg.strip)
end
def get_messages user
emails = Base::DB[:emails].where(authname: user.authname).select(:address).all.map(&:values).flatten
Base::DB[:messages].where(dest: [user.nick, user.authname] + emails).where(read_at: nil)
end
def get_addresses user
Base::DB[:emails].where(authname: user.authname)
end
end

42
plugins/root_me.rb Normal file
View File

@ -0,0 +1,42 @@
require "base64"
class RootMe < Botpop::Plugin
include Cinch::Plugin
FloatRegexp = "\d+(\.\d+)?"
match(/!ep1 (\w+)/, use_prefix: false, method: :start_ep1)
match(/!ep2 (\w+)/, use_prefix: false, method: :start_ep2)
match(/^(#{FloatRegexp}) ?\/ ?(#{FloatRegexp})$/, use_prefix: false, method: :play_ep1)
match(/^(\d+) ?\/ ?(\d+)$/, use_prefix: false, method: :play_ep1)
match(/^(\w+)$/, use_prefix: false, method: :play_ep2)
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
def start_ep1 m, botname
bot = User(botname)
bot.send "!ep1"
end
def start_ep2 m, botname
bot = User(botname)
bot.send "!ep2"
end
def play_ep1 m, n1, n2
r = n1.to_f**(0.5) * n2.to_f
str = "!ep1 -rep #{r.round 2}"
puts str
m.reply str
# response will be logged by the bot, check the log
end
def play_ep2 m, b64
r = Base64.decode64(b64)
str = "!ep2 -rep #{r}"
puts str
m.reply str
# response will be logged by the bot, check the log
end
end

16
plugins/say_goodbye.rb Normal file
View File

@ -0,0 +1,16 @@
#encoding: utf-8
class SayGoodBye < Botpop::Plugin
include Cinch::Plugin
match(/^!sg [\w\-\.].+/, use_prefix: false, method: :exec_sg)
HELP = ["!sg src_name"]
ENABLED = config['enable'].nil? ? true : config['enable']
def exec_sg m
arg = m.message.split.last
m.reply config[arg].sample
end
end

View File

@ -1,24 +1,21 @@
#encoding: utf-8
module BotpopPlugins
module Searchabe
class Searchable < Botpop::Plugin
include Cinch::Plugin
MATCH = lambda do |parent, plugin|
parent.on :message, /\!(#{CONFIG.keys.join('|')}) .+/ do |m| plugin.exec_search m end
end
CONFIG = Botpop::CONFIG['searchable'] || raise(MissingConfigurationZone, 'base')
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
ENABLED = config['enable'].nil? ? true : config['enable']
VALUES = CONFIG.values.map{|e|"!"+e}.join(', ')
KEYS = CONFIG.keys.map{|e|"!"+e}.join(', ')
HELP = CONFIG.keys.map{|e|"!"+e+" [search]"}
def self.exec_search m
msg = Builtin.get_msg m
url = CONFIG[m.params[1..-1].join(' ').gsub(/\!([^ ]+) .+/, '\1')]
url = url.gsub('___MSG___', msg)
m.reply url
end
VALUES = config.values.map{|e|"!"+e}.join(', ')
KEYS = config.keys.map{|e|"!"+e}.join(', ')
HELP = config.keys.map{|e|"!"+e+" [search]"}
CONFIG = config
match(/\!(#{config.keys.join('|')}) .+/, use_prefix: false, method: :exec_search)
def exec_search m
msg = Botpop::Builtins.get_msg m
url = CONFIG[m.params[1..-1].join(' ').gsub(/\!([^ ]+) .+/, '\1')]
url = url.gsub('___MSG___', msg)
m.reply url
end
end

32
plugins/taggle.rb Normal file
View File

@ -0,0 +1,32 @@
#encoding: utf-8
class Taggle < Botpop::Plugin
include Cinch::Plugin
match(/!tg (.+)/, use_prefix: false, method: :exec_tg)
HELP = ["!tg [nick]"]
CONFIG = config(safe: true) || {}
ENABLED = CONFIG['enable'].nil? ? true : CONFIG['enable']
NTIMES = CONFIG['ntimes'] || 10
WAIT = CONFIG['wait'] || 0.3
def cmd_allowed? m
return Base.cmd_allowed? m, ["tg"]
end
def exec_tg m, who
return if not cmd_allowed? m
@@tg_lock ||= Mutex.new
@@tg_lock.lock
begin
NTIMES.times do
User(who).send("tg #{who}")
sleep WAIT
end
ensure
@@tg_lock.unlock
end
end
end

36
plugins/youtube.rb Normal file
View File

@ -0,0 +1,36 @@
require 'mechanize'
class Youtube < Botpop::Plugin
include Cinch::Plugin
match(/!yt (.+)/, use_prefix: false, method: :find_youtube_video)
HELP = ["!yt title"]
ENABLED = config['enable'].nil? ? false : config['enable']
CONFIG = config
private
def search_url(title)
CONFIG['search_url'].gsub('___MSG___', title)
end
def reduce_url(url)
CONFIG['reduce_url'].gsub('___ID___', url.gsub(/^(.+)(v=)(\w+)$/, '\3'))
end
def display(result)
CONFIG['display']
.gsub('___TITLE___', result[:title])
.gsub('___URL___', reduce_url(result[:url]))
end
public
def find_youtube_video m, title
e = Mechanize.new
e.get(search_url(title))
result = {
title: e.page.at(".item-section li").at('h3').text,
url: e.page.at(".item-section li").at('a')[:href],
}
m.reply display(result)
end
end

24
test/test.rb Normal file
View File

@ -0,0 +1,24 @@
#encoding: utf-8
require "test/unit"
$botpop_include_verbose = false
require_relative "../botpop"
class TestBotbot < Test::Unit::TestCase
def test_binding_pry_existence
assert(`grep -R 'binding\\.pry' *.rb plugins/*.rb`.empty?)
end
def test_classes_constants
assert(Botpop.class == Class)
assert(Botpop::ARGUMENTS)
assert(Botpop::VERSION)
assert(Botpop::CONFIG)
assert(Botpop::TARGET)
assert(Botpop::PluginInclusion.class == Module)
assert(Botpop::Builtins.class == Module)
assert(Botpop::Plugin.class == Class)
end
end

View File

@ -1 +1 @@
v0.11.2-Smokeandalaconflol
v1.2-4