rodbot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data/CHANGELOG.md +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +653 -0
- data/exe/rodbot +7 -0
- data/lib/roda/plugins/rodbot.rb +36 -0
- data/lib/rodbot/async.rb +45 -0
- data/lib/rodbot/cli/command.rb +25 -0
- data/lib/rodbot/cli/commands/console.rb +23 -0
- data/lib/rodbot/cli/commands/credentials.rb +19 -0
- data/lib/rodbot/cli/commands/deploy.rb +20 -0
- data/lib/rodbot/cli/commands/new.rb +21 -0
- data/lib/rodbot/cli/commands/simulator.rb +17 -0
- data/lib/rodbot/cli/commands/start.rb +26 -0
- data/lib/rodbot/cli/commands/stop.rb +15 -0
- data/lib/rodbot/cli/commands/version.rb +15 -0
- data/lib/rodbot/cli/commands.rb +18 -0
- data/lib/rodbot/cli.rb +9 -0
- data/lib/rodbot/config.rb +157 -0
- data/lib/rodbot/constants.rb +13 -0
- data/lib/rodbot/db/hash.rb +71 -0
- data/lib/rodbot/db/redis.rb +61 -0
- data/lib/rodbot/db.rb +91 -0
- data/lib/rodbot/dispatcher.rb +125 -0
- data/lib/rodbot/env.rb +48 -0
- data/lib/rodbot/error.rb +19 -0
- data/lib/rodbot/generator.rb +108 -0
- data/lib/rodbot/log.rb +67 -0
- data/lib/rodbot/memoize.rb +86 -0
- data/lib/rodbot/plugins/github_webhook/README.github_webhook.md +42 -0
- data/lib/rodbot/plugins/github_webhook/app.rb +46 -0
- data/lib/rodbot/plugins/gitlab_webhook/README.gitlab_webhook.md +40 -0
- data/lib/rodbot/plugins/gitlab_webhook/app.rb +40 -0
- data/lib/rodbot/plugins/hal/README.hal.md +15 -0
- data/lib/rodbot/plugins/hal/app.rb +22 -0
- data/lib/rodbot/plugins/matrix/README.matrix.md +42 -0
- data/lib/rodbot/plugins/matrix/relay.rb +113 -0
- data/lib/rodbot/plugins/otp/README.otp.md +82 -0
- data/lib/rodbot/plugins/otp/app.rb +47 -0
- data/lib/rodbot/plugins/word_of_the_day/README.word_of_the_day.md +13 -0
- data/lib/rodbot/plugins/word_of_the_day/schedule.rb +51 -0
- data/lib/rodbot/plugins.rb +81 -0
- data/lib/rodbot/rack.rb +50 -0
- data/lib/rodbot/refinements.rb +118 -0
- data/lib/rodbot/relay.rb +104 -0
- data/lib/rodbot/services/app.rb +72 -0
- data/lib/rodbot/services/relay.rb +37 -0
- data/lib/rodbot/services/schedule.rb +29 -0
- data/lib/rodbot/services.rb +32 -0
- data/lib/rodbot/simulator.rb +60 -0
- data/lib/rodbot/version.rb +5 -0
- data/lib/rodbot.rb +60 -0
- data/lib/templates/deploy/docker/compose.yaml.gerb +37 -0
- data/lib/templates/deploy/docker-split/compose.yaml.gerb +52 -0
- data/lib/templates/deploy/procfile/Procfile.gerb +1 -0
- data/lib/templates/deploy/procfile-split/Procfile.gerb +5 -0
- data/lib/templates/deploy/render/render.yaml.gerb +0 -0
- data/lib/templates/deploy/render-split/render.yaml.gerb +0 -0
- data/lib/templates/new/LICENSE.txt +22 -0
- data/lib/templates/new/README.md +4 -0
- data/lib/templates/new/app/app.rb +11 -0
- data/lib/templates/new/app/routes/help.rb +19 -0
- data/lib/templates/new/app/views/layout.erb +12 -0
- data/lib/templates/new/app/views/root.erb +5 -0
- data/lib/templates/new/config/rodbot.rb +8 -0
- data/lib/templates/new/config/schedule.rb +5 -0
- data/lib/templates/new/config.ru +3 -0
- data/lib/templates/new/gems.locked +104 -0
- data/lib/templates/new/gems.rb +15 -0
- data/lib/templates/new/guardfile.rb +9 -0
- data/lib/templates/new/public/assets/images/rodbot.avif +0 -0
- data/lib/templates/new/public/assets/stylesheets/base.css +18 -0
- data/lib/templates/new/rakefile.rb +28 -0
- data.tar.gz.sig +0 -0
- metadata +510 -0
- metadata.gz.sig +3 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'puma'
|
5
|
+
require 'roda'
|
6
|
+
|
7
|
+
module Rodbot
|
8
|
+
class Services
|
9
|
+
class App
|
10
|
+
include Rodbot::Memoize
|
11
|
+
|
12
|
+
class << self
|
13
|
+
include Rodbot::Memoize
|
14
|
+
|
15
|
+
# URL (including port) to reach the app service locally
|
16
|
+
#
|
17
|
+
# @return [String] URL
|
18
|
+
memoize def url
|
19
|
+
[
|
20
|
+
(ENV['RODBOT_APP_URL'] || 'http://localhost'),
|
21
|
+
Rodbot.config(:port)
|
22
|
+
].join(':')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def tasks(**)
|
27
|
+
puts "Starting app service on http://#{bind.join(':')}"
|
28
|
+
[method(:run)]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def run
|
34
|
+
Dir.chdir(Rodbot.env.root)
|
35
|
+
Puma::Server.new(app, nil, options).tap do |server|
|
36
|
+
server.add_tcp_listener(*bind)
|
37
|
+
server.app = ::Rack::CommonLogger.new(app, logger)
|
38
|
+
end.run.join
|
39
|
+
end
|
40
|
+
|
41
|
+
memoize def bind
|
42
|
+
[
|
43
|
+
(ENV['RODBOT_APP_HOST'] || 'localhost'),
|
44
|
+
Rodbot.config(:port)
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
memoize def app
|
49
|
+
::Rack::Builder.parse_file(Rodbot.env.root.join('config.ru').to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
def options
|
53
|
+
{
|
54
|
+
lowlevel_error_handler: method(:lowlevel_error_handler),
|
55
|
+
log_writer: Puma::LogWriter.null,
|
56
|
+
min_threads: Rodbot.config(:app, :threads).min,
|
57
|
+
max_threads: Rodbot.config(:app, :threads).max
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
memoize def logger
|
62
|
+
Rodbot::Log.logger('app')
|
63
|
+
end
|
64
|
+
|
65
|
+
def lowlevel_error_handler(error)
|
66
|
+
logger.error("#{error.message}: #{error.backtrace.first}")
|
67
|
+
[500, {}, ['Oops!']]
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
using Rodbot::Refinements
|
4
|
+
|
5
|
+
module Rodbot
|
6
|
+
class Services
|
7
|
+
class Relay
|
8
|
+
|
9
|
+
class << self
|
10
|
+
include Rodbot::Memoize
|
11
|
+
|
12
|
+
# URL (including port) to reach the given relay service locally
|
13
|
+
#
|
14
|
+
# @param name [Symbol] relay service
|
15
|
+
# @return [String] URL
|
16
|
+
memoize def url(name)
|
17
|
+
[
|
18
|
+
(ENV["RODBOT_RELAY_URL_#{name.upcase}"] || 'tcp://localhost'),
|
19
|
+
Rodbot.config(:port) + 1 + Rodbot.config(:plugin).keys.index(name)
|
20
|
+
].join(':')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def tasks(only: nil)
|
25
|
+
Rodbot.plugins.extend_relay
|
26
|
+
extensions = Rodbot.plugins.extensions[:relay]
|
27
|
+
extensions.select! { _1 == only.to_sym } if only
|
28
|
+
fail Rodbot::RelayError, "no matching relay plugin configured" if extensions.none?
|
29
|
+
extensions.map do |name, path|
|
30
|
+
puts "Starting relay service extension #{name} on #{self.class.url(name)}"
|
31
|
+
path.constantize.new.loops
|
32
|
+
end.flatten
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'clockwork'
|
4
|
+
require 'active_support/time'
|
5
|
+
|
6
|
+
module Rodbot
|
7
|
+
class Services
|
8
|
+
class Schedule
|
9
|
+
|
10
|
+
def tasks(**)
|
11
|
+
puts "Starting schedule service"
|
12
|
+
[method(:run)]
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def run
|
18
|
+
Clockwork.instance_eval do
|
19
|
+
configure { _1[:logger] = Rodbot::Log.logger('schedule') }
|
20
|
+
handler { Rodbot::Async.perform(&_1) }
|
21
|
+
end
|
22
|
+
Rodbot.plugins.extend_schedule
|
23
|
+
require Rodbot.env.root.join('config', 'schedule')
|
24
|
+
Clockwork.run
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
using Rodbot::Refinements
|
4
|
+
|
5
|
+
module Rodbot
|
6
|
+
|
7
|
+
# Foundation to run app, relay and schedule services
|
8
|
+
class Services
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegator :@dispatcher, :run, :run
|
12
|
+
def_delegator :@dispatcher, :interrupt, :interrupt
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@dispatcher = Rodbot::Dispatcher.new('rodbot')
|
16
|
+
end
|
17
|
+
|
18
|
+
def exist?(service)
|
19
|
+
Rodbot::SERVICES.include? service.to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
def register(service, extension: nil)
|
23
|
+
fail(Rodbot::ServiceError, "unknown service #{service}") unless exist? service
|
24
|
+
tasks = "rodbot/services/#{service}".constantize.new.tasks(only: extension)
|
25
|
+
tasks.each_with_index do |task, index|
|
26
|
+
name = [service, (index if tasks.count > 1)].compact.join('-')
|
27
|
+
@dispatcher.register(name, &task)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'readline'
|
4
|
+
require 'httparty'
|
5
|
+
require 'pastel'
|
6
|
+
require 'tty-markdown'
|
7
|
+
|
8
|
+
using Rodbot::Refinements
|
9
|
+
|
10
|
+
module Rodbot
|
11
|
+
|
12
|
+
# Simulate a chat client
|
13
|
+
class Simulator
|
14
|
+
|
15
|
+
# @param sender [String] sender to mimick
|
16
|
+
# @param raw [Boolean] whether to display raw Markdown
|
17
|
+
def initialize(sender, raw: false)
|
18
|
+
@sender, @raw = sender, raw
|
19
|
+
@pastel = Pastel.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
puts nil, "Talking to app on #{Rodbot::Services::App.url} as sender #{@pastel.inverse(@sender)}."
|
24
|
+
puts 'Type commands beginning with "!" or empty line to exit.', nil
|
25
|
+
while (line = Readline.readline("rodbot> ", true)) && !line.empty?
|
26
|
+
puts nil, reply_to(line), nil
|
27
|
+
end
|
28
|
+
puts
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def reply_to(message)
|
34
|
+
return "(no command given)" unless message.match?(/^!/)
|
35
|
+
command, argument = message[1..].split(/\s+/, 2)
|
36
|
+
body = begin
|
37
|
+
response = Rodbot.request(command, query: { argument: argument })
|
38
|
+
case response.code
|
39
|
+
when 200 then response.body
|
40
|
+
when 404 then "[[SENDER]] I've never heard of `!#{command}`, try `!help` instead. 🤔"
|
41
|
+
else fail
|
42
|
+
end
|
43
|
+
rescue
|
44
|
+
"[[SENDER]] I'm having trouble talking to the app. 💣"
|
45
|
+
end
|
46
|
+
text_for body.psub(placeholders)
|
47
|
+
end
|
48
|
+
|
49
|
+
def placeholders
|
50
|
+
{
|
51
|
+
sender: @pastel.inverse(@sender)
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def text_for(markdown)
|
56
|
+
@raw ? markdown : TTY::Markdown.parse(markdown, mode: 16).strip
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/rodbot.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
require 'zeitwerk'
|
6
|
+
require 'dry/credentials'
|
7
|
+
require 'logger'
|
8
|
+
|
9
|
+
loader = Zeitwerk::Loader.for_gem
|
10
|
+
loader.inflector.inflect 'cli' => 'CLI'
|
11
|
+
%w(rodbot/plugins roda templates).each { loader.ignore "#{__dir__}/#{_1}" }
|
12
|
+
loader.setup
|
13
|
+
|
14
|
+
# Rodbot foundation
|
15
|
+
#
|
16
|
+
# Once the Rodbot gem has been required, use +boot+ to spin up the foundation:
|
17
|
+
#
|
18
|
+
# Rodbot.boot # current directory is root directory
|
19
|
+
# Rodbot.boot(root: '/path/to/root') # explicit root directory
|
20
|
+
#
|
21
|
+
# This gives you access to the following shortcuts (in order of loading):
|
22
|
+
#
|
23
|
+
# * +Rodbot.env+ -> {Rodbot::Env}
|
24
|
+
# * +Rodbot.credentials+ -> {Dry::Credentials}
|
25
|
+
# * +Rodbot.config+ -> {Rodbot::Config#config}
|
26
|
+
# * +Rodbot.plugins+ -> {Rodbot::Plugins}
|
27
|
+
# * +Rodbot.db+ -> {Rodbot::Db#db}
|
28
|
+
# * +Rodbot.log+ -> {Rodbot::Log#log}
|
29
|
+
# * +Rodbot.request+ -> {Rodbot::Rack#request}
|
30
|
+
# * +Rodbot.say+ -> {Rodbot::Relay#say}
|
31
|
+
module Rodbot
|
32
|
+
include Rodbot::Constants
|
33
|
+
extend Dry::Credentials
|
34
|
+
|
35
|
+
class << self
|
36
|
+
extend Forwardable
|
37
|
+
|
38
|
+
attr_reader :env
|
39
|
+
def_delegator :@config, :config
|
40
|
+
def_delegator :@plugins, :itself, :plugins
|
41
|
+
def_delegator :@db, :itself, :db
|
42
|
+
def_delegator :@log, :log
|
43
|
+
def_delegator 'Rodbot::Rack', :request
|
44
|
+
def_delegator 'Rodbot::Relay', :say
|
45
|
+
|
46
|
+
def boot(root: nil)
|
47
|
+
@env = Rodbot::Env.new(root: root)
|
48
|
+
credentials do
|
49
|
+
env Rodbot.env.current
|
50
|
+
dir ENV['RODBOT_CREDENTIALS_DIR'] || Rodbot.env.root.join('config', 'credentials')
|
51
|
+
end
|
52
|
+
@config = Rodbot::Config.new(Rodbot.env.root.join('config', 'rodbot.rb').read)
|
53
|
+
@plugins = Rodbot::Plugins.new
|
54
|
+
@db = (db = @config.config(:db)) && Rodbot::Db.new(db)
|
55
|
+
@log = Rodbot::Log.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
loader.eager_load_namespace(Rodbot::Error)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
version: "3.9"
|
2
|
+
|
3
|
+
x-defaults: &defaults
|
4
|
+
build:
|
5
|
+
context: .
|
6
|
+
dockerfile_inline: |
|
7
|
+
FROM ruby:3.2-alpine
|
8
|
+
RUN apk update && apk --no-cache add build-base
|
9
|
+
ENV RODBOT_ENV="production"
|
10
|
+
ENV RACK_ENV="production"
|
11
|
+
ENV RACK_ROOT="/var/www"
|
12
|
+
ENV TZ="[%= timezone %]"
|
13
|
+
RUN mkdir -p /var/www
|
14
|
+
WORKDIR /var/www
|
15
|
+
COPY . .
|
16
|
+
COPY .bundle /usr/local/bundle
|
17
|
+
RUN bundle config set without "development test" && \
|
18
|
+
bundle install --jobs 20 --retry 5
|
19
|
+
environment:
|
20
|
+
- RODBOT_APP_HOST=0.0.0.0
|
21
|
+
- PRODUCTION_CREDENTIALS_KEY
|
22
|
+
restart: "unless-stopped"
|
23
|
+
|
24
|
+
services:
|
25
|
+
rodbot:
|
26
|
+
<<: *defaults
|
27
|
+
command: "sh -c 'bundle exec rodbot start && sleep infinity'"
|
28
|
+
ports:
|
29
|
+
- "[%= Rodbot.config(:app, :port) %]"
|
30
|
+
|
31
|
+
networks:
|
32
|
+
default:
|
33
|
+
driver: "bridge"
|
34
|
+
ipam:
|
35
|
+
driver: "default"
|
36
|
+
config:
|
37
|
+
- subnet: "172.16.72.0/24"
|
@@ -0,0 +1,52 @@
|
|
1
|
+
version: "3.9"
|
2
|
+
|
3
|
+
x-defaults: &defaults
|
4
|
+
build:
|
5
|
+
context: .
|
6
|
+
dockerfile_inline: |
|
7
|
+
FROM ruby:3.2-alpine
|
8
|
+
RUN apk update && apk --no-cache add build-base
|
9
|
+
ENV RODBOT_ENV="production"
|
10
|
+
ENV RACK_ENV="production"
|
11
|
+
ENV RACK_ROOT="/var/www"
|
12
|
+
ENV TZ="[%= timezone %]"
|
13
|
+
RUN mkdir -p /var/www
|
14
|
+
WORKDIR /var/www
|
15
|
+
COPY . .
|
16
|
+
COPY .bundle /usr/local/bundle
|
17
|
+
RUN bundle config set without "development test" && \
|
18
|
+
bundle install --jobs 20 --retry 5
|
19
|
+
environment:
|
20
|
+
- RODBOT_APP_HOST=0.0.0.0
|
21
|
+
- RODBOT_APP_URL=http://app
|
22
|
+
- RODBOT_RELAY_HOST=0.0.0.0
|
23
|
+
[% relay_extensions.each do |name, _| -%]
|
24
|
+
- RODBOT_RELAY_URL_[%= name.upcase %]=tcp://relay-[%= name %]
|
25
|
+
[% end -%]
|
26
|
+
- PRODUCTION_CREDENTIALS_KEY
|
27
|
+
restart: "unless-stopped"
|
28
|
+
|
29
|
+
services:
|
30
|
+
app:
|
31
|
+
<<: *defaults
|
32
|
+
command: "bundle exec rodbot start app"
|
33
|
+
ports:
|
34
|
+
- "[%= Rodbot.config(:app, :port) %]"
|
35
|
+
schedule:
|
36
|
+
<<: *defaults
|
37
|
+
command: "bundle exec rodbot start schedule"
|
38
|
+
[% relay_extensions.each do |name, port| -%]
|
39
|
+
relay-[%= name %]:
|
40
|
+
<<: *defaults
|
41
|
+
command: "bundle exec rodbot start relay [%= name %]"
|
42
|
+
expose:
|
43
|
+
- [%= port %]
|
44
|
+
[% end -%]
|
45
|
+
|
46
|
+
networks:
|
47
|
+
default:
|
48
|
+
driver: "bridge"
|
49
|
+
ipam:
|
50
|
+
driver: "default"
|
51
|
+
config:
|
52
|
+
- subnet: "172.16.72.0/24"
|
@@ -0,0 +1 @@
|
|
1
|
+
rodbot: bundle exec rodbot start
|
File without changes
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sven Schwyn
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Routes
|
2
|
+
class Help < App
|
3
|
+
|
4
|
+
route do |r|
|
5
|
+
|
6
|
+
# GET /help
|
7
|
+
r.root do
|
8
|
+
response['Content-Type'] = 'text/markdown; charset=utf-8'
|
9
|
+
<<~END
|
10
|
+
[[SENDER]] I'm Rodbot, what can I do for you today?
|
11
|
+
|
12
|
+
* `!ping` – check whether I'm listening
|
13
|
+
END
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
6
|
+
<title>title</title>
|
7
|
+
<link rel="stylesheet" href="/assets/stylesheets/base.css">
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<%= yield %>
|
11
|
+
</body>
|
12
|
+
</html>
|
@@ -0,0 +1,104 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../../..
|
3
|
+
specs:
|
4
|
+
rodbot (0.1.0.pre1)
|
5
|
+
clockwork (~> 3)
|
6
|
+
debug
|
7
|
+
dry-cli (~> 1)
|
8
|
+
dry-credentials (~> 0)
|
9
|
+
httparty (~> 0)
|
10
|
+
kramdown (~> 2)
|
11
|
+
kramdown-parser-gfm (~> 1)
|
12
|
+
matrix_sdk (~> 2)
|
13
|
+
pastel (~> 0)
|
14
|
+
puma (~> 6, >= 6.2)
|
15
|
+
roda (~> 3)
|
16
|
+
rotp (~> 6)
|
17
|
+
sucker_punch (~> 3)
|
18
|
+
tilt (~> 2)
|
19
|
+
tty-markdown (~> 0)
|
20
|
+
zeitwerk (~> 2)
|
21
|
+
|
22
|
+
GEM
|
23
|
+
remote: https://rubygems.org/
|
24
|
+
specs:
|
25
|
+
activesupport (7.0.4.3)
|
26
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
27
|
+
i18n (>= 1.6, < 2)
|
28
|
+
minitest (>= 5.1)
|
29
|
+
tzinfo (~> 2.0)
|
30
|
+
clockwork (3.0.2)
|
31
|
+
activesupport
|
32
|
+
tzinfo
|
33
|
+
concurrent-ruby (1.2.2)
|
34
|
+
debug (1.8.0)
|
35
|
+
irb (>= 1.5.0)
|
36
|
+
reline (>= 0.3.1)
|
37
|
+
dry-cli (1.0.0)
|
38
|
+
dry-credentials (0.1.0)
|
39
|
+
httparty (0.21.0)
|
40
|
+
mini_mime (>= 1.0.0)
|
41
|
+
multi_xml (>= 0.5.2)
|
42
|
+
i18n (1.12.0)
|
43
|
+
concurrent-ruby (~> 1.0)
|
44
|
+
io-console (0.6.0)
|
45
|
+
irb (1.6.4)
|
46
|
+
reline (>= 0.3.0)
|
47
|
+
kramdown (2.4.0)
|
48
|
+
rexml
|
49
|
+
kramdown-parser-gfm (1.1.0)
|
50
|
+
kramdown (~> 2.0)
|
51
|
+
little-plugger (1.1.4)
|
52
|
+
logging (2.3.1)
|
53
|
+
little-plugger (~> 1.1)
|
54
|
+
multi_json (~> 1.14)
|
55
|
+
matrix_sdk (2.8.0)
|
56
|
+
logging (~> 2)
|
57
|
+
mini_mime (1.1.2)
|
58
|
+
minitest (5.18.0)
|
59
|
+
multi_json (1.15.0)
|
60
|
+
multi_xml (0.6.0)
|
61
|
+
nio4r (2.5.8)
|
62
|
+
pastel (0.8.0)
|
63
|
+
tty-color (~> 0.5)
|
64
|
+
puma (6.2.0)
|
65
|
+
nio4r (~> 2.0)
|
66
|
+
rack (3.0.7)
|
67
|
+
reline (0.3.3)
|
68
|
+
io-console (~> 0.5)
|
69
|
+
rexml (3.2.5)
|
70
|
+
roda (3.66.0)
|
71
|
+
rack
|
72
|
+
rotp (6.2.2)
|
73
|
+
rouge (4.1.0)
|
74
|
+
strings (0.2.1)
|
75
|
+
strings-ansi (~> 0.2)
|
76
|
+
unicode-display_width (>= 1.5, < 3.0)
|
77
|
+
unicode_utils (~> 1.4)
|
78
|
+
strings-ansi (0.2.0)
|
79
|
+
sucker_punch (3.1.0)
|
80
|
+
concurrent-ruby (~> 1.0)
|
81
|
+
tilt (2.1.0)
|
82
|
+
tty-color (0.6.0)
|
83
|
+
tty-markdown (0.7.2)
|
84
|
+
kramdown (>= 1.16.2, < 3.0)
|
85
|
+
pastel (~> 0.8)
|
86
|
+
rouge (>= 3.14, < 5.0)
|
87
|
+
strings (~> 0.2.0)
|
88
|
+
tty-color (~> 0.5)
|
89
|
+
tty-screen (~> 0.8)
|
90
|
+
tty-screen (0.8.1)
|
91
|
+
tzinfo (2.0.6)
|
92
|
+
concurrent-ruby (~> 1.0)
|
93
|
+
unicode-display_width (2.4.2)
|
94
|
+
unicode_utils (1.4.0)
|
95
|
+
zeitwerk (2.6.7)
|
96
|
+
|
97
|
+
PLATFORMS
|
98
|
+
arm64-darwin-22
|
99
|
+
|
100
|
+
DEPENDENCIES
|
101
|
+
rodbot!
|
102
|
+
|
103
|
+
BUNDLED WITH
|
104
|
+
2.4.12
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'rodbot', '~> 0'
|
4
|
+
|
5
|
+
group :matrix, optional: true do
|
6
|
+
gem 'matrix_sdk', '~> 2'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :redis, optional: true do
|
10
|
+
gem 'redis', '~> 5'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :otp, optional: true do
|
14
|
+
gem 'rotp', '~> 6'
|
15
|
+
end
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
main {
|
2
|
+
display: flex;
|
3
|
+
justify-content: center;
|
4
|
+
align-items: center;
|
5
|
+
height: 100vh;
|
6
|
+
}
|
7
|
+
|
8
|
+
a {
|
9
|
+
display: flex;
|
10
|
+
justify-content: center;
|
11
|
+
align-items: center;
|
12
|
+
width: 50%;
|
13
|
+
}
|
14
|
+
|
15
|
+
a img {
|
16
|
+
max-width: 100%;
|
17
|
+
height: auto;
|
18
|
+
}
|