~xdavidwu/xdavidwu.link

18cd8fb08fd5954b17f36a2f796cfe57f7f1c785 — xdavidwu 3 years ago f3edb4b
add matrix commenting based on cactus

instead of using an appservice, we use a bot user to provision rooms for
us.
M _config.yml => _config.yml +7 -1
@@ 33,7 33,7 @@ masthead_title: # overrides the website title displayed in the masthead, use " "
# breadcrumbs: false # true, false (default)
words_per_minute: 200
comments:
  provider: "disqus" # false (default), "disqus", "discourse", "facebook", "google-plus", "staticman", "staticman_v2" "custom"
  provider: "matrix" # false (default), "disqus", "discourse", "facebook", "google-plus", "staticman", "staticman_v2" "custom"
  disqus:
    shortname: "parto-blog" # https://help.disqus.com/customer/portal/articles/466208-what-s-a-shortname-
  discourse:


@@ 49,6 49,12 @@ comments:
  staticman:
    branch: # "master"
    endpoint: # "https://{your Staticman v3 API}/v3/entry/github/"
  matrix:
    homeserver_url: "https://eglo.ga"
    homeserver: "eglo.ga"
    site: "xdavidwu.eglo.ga"
    admin: "@xdavidwu:eglo.ga"
    bot: "@xdavidwu.eglo.ga-comment-bot:eglo.ga"
reCaptcha:
  siteKey:
  secret:

A _includes/comments-providers/matrix.html => _includes/comments-providers/matrix.html +10 -0
@@ 0,0 1,10 @@
<script>
  initComments({
    node: document.getElementById('comment-section'),
    defaultHomeserverUrl: 'https://matrix-client.matrix.org',
    serverName: '{{ site.comments.matrix.homeserver }}',
    siteName: '{{ site.comments.matrix.site }}',
    commentSectionId: '{{ page.url }}',
    guestPostingEnabled: false,
  })
</script>

M _includes/comments-providers/scripts.html => _includes/comments-providers/scripts.html +2 -0
@@ 12,6 12,8 @@
    {% include /comments-providers/staticman_v2.html %}
  {% when "utterances" %}
    {% include /comments-providers/utterances.html %}
  {% when "matrix" %}
    {% include /comments-providers/matrix.html %}
  {% when "custom" %}
    {% include /comments-providers/custom_scripts.html %}
{% endcase %}

M _includes/comments.html => _includes/comments.html +3 -0
@@ 155,6 155,9 @@
    {% when "utterances" %}
      <h4 class="page__comments-title">{{ comments_label }}</h4>
      <section id="utterances-comments"></section>
    {% when "matrix" %}
      <h4 class="page__comments-title">Comments on Matrix #comments_{{ site.comments.matrix.site }}_{{ page.url }}:{{ site.comments.matrix.homeserver }}</h4>
      <div id="comment-section"></div>
    {% when "custom" %}
      {% include /comments-providers/custom.html %}
  {% endcase %}

M _includes/head.html => _includes/head.html +4 -0
@@ 7,6 7,10 @@
<script>
  document.documentElement.className = '';
</script>
{% if site.comments.provider == "matrix" and page.comments %}
  <script type="text/javascript" src="https://latest.cactus.chat/cactus.js"></script>
  <link rel="stylesheet" href="https://latest.cactus.chat/style.css" type="text/css">
{% endif %}
<link rel="stylesheet" href="{{ '/assets/css/main.css' | relative_url }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/fork-awesome.min.css" integrity="sha256-gsmEoJAws/Kd3CjuOQzLie5Q3yshhvmo7YNtBG7aaEY=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.1.7/css/v5-compat.min.css" integrity="sha384-1zW94WHdRLtWmM3xxKcAULg/IDeSsb7kofYSkI2jlXTRLO9UXrZcxB1Xi7jQ18Fg" crossorigin="anonymous">

A _plugins/matrix-room-provision.rb => _plugins/matrix-room-provision.rb +60 -0
@@ 0,0 1,60 @@
require 'net/http'
require 'json'

Jekyll::Hooks.register :site, :after_init do |site|
  $config = site.config
end

Jekyll::Hooks.register :posts, :post_write do |page|
  if $config['comments']['provider'] != 'matrix'
    return
  end

  Jekyll.logger.info 'Checking Matrix room for post:',  page.data['title']
  hs_url = $config['comments']['matrix']['homeserver_url']
  hs = $config['comments']['matrix']['homeserver']
  site = $config['comments']['matrix']['site']
  room_alias_local = "comments_#{site}_#{page.url}"
  room_alias = "##{room_alias_local}:#{hs}"

  alias_encoded = ERB::Util.url_encode room_alias
  alias_resolve_uri = URI hs_url + "/_matrix/client/r0/directory/room/#{alias_encoded}"
  res = Net::HTTP.get_response alias_resolve_uri

  if res.is_a? Net::HTTPNotFound
    Jekyll.logger.info 'Creating Matrix room:', room_alias
    create_room_uri = URI hs_url + '/_matrix/client/r0/createRoom'
    req = Net::HTTP::Post.new create_room_uri, 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{ENV['MATRIX_ACCESS_TOKEN']}"
    req.body = {
      visibility: 'private',
      room_alias_name: room_alias_local,
      name: "#{page.data['title']}",
      topic: "Comments of \"#{page.data['title']}\" in #{site} at #{$config['url'] + page.url}",
      invite: [$config['comments']['matrix']['admin']],
      creation_content: {
        'm.federate': true,
      },
      preset: 'public_chat',
      initial_state: [
        {
          type: 'm.room.history_visibility',
          content: {
            history_visibility: 'world_readable',
          },
        },
      ],
      power_level_content_override: {
        users: {
          $config['comments']['matrix']['admin'] => 100,
          $config['comments']['matrix']['bot'] => 100,
        },
      },
    }.to_json
    res = Net::HTTP.start create_room_uri.hostname, create_room_uri.port, use_ssl: true do |http|
      http.request req
    end
    Jekyll.logger.info "createRoom returns:", res.body
  end

  Jekyll.logger.info ""
end

M _sass/minimal-mistakes/_buttons.scss => _sass/minimal-mistakes/_buttons.scss +1 -1
@@ 6,7 6,7 @@
   Default button
   ========================================================================== */

.btn {
.btn, .cactus-button {
  /* default */
  display: inline-block;
  margin-bottom: 0.25em;

M _sass/minimal-mistakes/_colors.scss => _sass/minimal-mistakes/_colors.scss +12 -0
@@ 597,3 597,15 @@ a.reversefootnote {
.required {
  color: $danger-color;
}

@if $comments-provider == matrix {
  .cactus-login-form {
    background-color: $background-color;
  }
  .cactus-login-field {
    > input {
      border-color: $border-color;
      color: $text-color;
    }
  }
}

M _sass/minimal-mistakes/_forms.scss => _sass/minimal-mistakes/_forms.scss +91 -60
@@ 2,18 2,18 @@
  /* ==========================================================================
     Forms
     ========================================================================== */
  

  form {
    margin: 0 0 5px 0;
    padding: 1em;
    background-color: $form-background-color;
  

    fieldset {
      margin-bottom: 5px;
      padding: 0;
      border-width: 0;
    }
  

    legend {
      display: block;
      width: 100%;


@@ 23,22 23,22 @@
      border: 0;
      white-space: normal;
    }
  

    p {
      margin-bottom: (5px / 2);
    }
  

    ul {
      list-style-type: none;
      margin: 0 0 5px 0;
      padding: 0;
    }
  

    br {
      display: none;
    }
  }
  

  label,
  input,
  button,


@@ 46,31 46,31 @@
  textarea {
    vertical-align: baseline;
  }
  

  input,
  button,
  select,
  textarea {
    box-sizing: border-box;
  }
  

  label {
    display: block;
    margin-bottom: 0.25em;
    color: $text-color;
    cursor: pointer;
  

    small {
      font-size: $type-size-6;
    }
  

    input,
    textarea,
    select {
      display: block;
    }
  }
  

  input,
  textarea,
  select {


@@ 84,15 84,15 @@
    border-radius: $border-radius;
    box-shadow: $box-shadow;
  }
  

  .input-mini {
    width: 60px;
  }
  

  .input-small {
    width: 90px;
  }
  

  input[type="image"],
  input[type="checkbox"],
  input[type="radio"] {


@@ 105,17 105,17 @@
    border-radius: 0;
    box-shadow: none;
  }
  

  input[type="checkbox"],
  input[type="radio"] {
    box-sizing: border-box;
    padding: 0;
  }
  

  input[type="image"] {
    border: 0;
  }
  

  input[type="file"] {
    width: auto;
    padding: initial;


@@ 125,7 125,7 @@
    background-color: initial;
    box-shadow: none;
  }
  

  input[type="button"],
  input[type="reset"],
  input[type="submit"] {


@@ 133,44 133,44 @@
    height: auto;
    cursor: pointer;
  }
  

  select {
    width: auto;
    background-color: #fff;
  }
  

  select[multiple],
  select[size] {
    height: auto;
  }
  

  textarea {
    resize: vertical;
    height: auto;
    overflow: auto;
    vertical-align: top;
  }
  

  input[type="hidden"] {
    display: none;
  }
  

  .form {
    position: relative;
  }
  

  .radio,
  .checkbox {
    padding-left: 18px;
    font-weight: normal;
  }
  

  .radio input[type="radio"],
  .checkbox input[type="checkbox"] {
    float: left;
    margin-left: -18px;
  }
  

  .radio.inline,
  .checkbox.inline {
    display: inline-block;


@@ 178,16 178,16 @@
    margin-bottom: 0;
    vertical-align: middle;
  }
  

  .radio.inline + .radio.inline,
  .checkbox.inline + .checkbox.inline {
    margin-left: 10px;
  }
  

  /*
       Disabled state
       ========================================================================== */
  

  input[disabled],
  select[disabled],
  textarea[disabled],


@@ 197,11 197,11 @@
    opacity: 0.5;
    cursor: not-allowed;
  }
  

  /*
       Focus & active state
       ========================================================================== */
  

  input:focus,
  textarea:focus {
    border-color: $primary-color;


@@ 209,60 209,60 @@
    box-shadow: inset 0 1px 3px rgba($text-color, 0.06),
      0 0 5px rgba($primary-color, 0.7);
  }
  

  input[type="file"]:focus,
  input[type="radio"]:focus,
  input[type="checkbox"]:focus,
  select:focus {
    box-shadow: none;
  }
  

  /*
       Help text
       ========================================================================== */
  

  .help-block,
  .help-inline {
    color: $muted-text-color;
  }
  

  .help-block {
    display: block;
    margin-bottom: 1em;
    line-height: 1em;
  }
  

  .help-inline {
    display: inline-block;
    vertical-align: middle;
    padding-left: 5px;
  }
  

  /*
       .form-group
       ========================================================================== */
  

  .form-group {
    margin-bottom: 5px;
    padding: 0;
    border-width: 0;
  }
  

  /*
       .form-inline
       ========================================================================== */
  

  .form-inline input,
  .form-inline textarea,
  .form-inline select {
    display: inline-block;
    margin-bottom: 0;
  }
  

  .form-inline label {
    display: inline-block;
  }
  

  .form-inline .radio,
  .form-inline .checkbox,
  .form-inline .radio {


@@ 270,36 270,36 @@
    margin-bottom: 0;
    vertical-align: middle;
  }
  

  .form-inline .radio input[type="radio"],
  .form-inline .checkbox input[type="checkbox"] {
    float: left;
    margin-left: 0;
    margin-right: 3px;
  }
  

  /*
       .form-search
       ========================================================================== */
  

  .form-search input,
  .form-search textarea,
  .form-search select {
    display: inline-block;
    margin-bottom: 0;
  }
  

  .form-search .search-query {
    padding-left: 14px;
    padding-right: 14px;
    margin-bottom: 0;
    border-radius: 14px;
  }
  

  .form-search label {
    display: inline-block;
  }
  

  .form-search .radio,
  .form-search .checkbox,
  .form-inline .radio {


@@ 307,26 307,26 @@
    margin-bottom: 0;
    vertical-align: middle;
  }
  

  .form-search .radio input[type="radio"],
  .form-search .checkbox input[type="checkbox"] {
    float: left;
    margin-left: 0;
    margin-right: 3px;
  }
  

  /*
       .form--loading
       ========================================================================== */
  

  .form--loading:before {
    content: "";
  }
  

  .form--loading .form__spinner {
    display: block;
  }
  

  .form:before {
    position: absolute;
    top: 0;


@@ 336,7 336,7 @@
    background-color: rgba(255, 255, 255, 0.7);
    z-index: 10;
  }
  

  .form__spinner {
    display: none;
    position: absolute;


@@ 344,11 344,11 @@
    left: 50%;
    z-index: 11;
  }
  

  /*
       Google search form
       ========================================================================== */
  

  #goog-fixurl {
    ul {
      list-style: none;


@@ 359,7 359,7 @@
      }
    }
  }
  

  #goog-wm-qt {
    width: auto;
    margin-right: 10px;


@@ 374,9 374,40 @@
    border-color: $border-color;
    border-radius: $border-radius;
  }
  

  #goog-wm-sb {
    @extend .btn;
  }
   

}
@if $comments-provider == matrix {
  .cactus-editor-textarea {
    border-radius: $border-radius;
    height: 120px;

    &::placeholder {
      line-height: 100px;
      font-size: 1em;
    }
  }

  // matrix.to fails with slash in localpart
  .cactus-matrixdotto-button {
    display: none !important;
  }

  .cactus-login-form {
    box-shadow: 0 2px 4px 0 rgba(#000, 0.16), 0 2px 10px 0 rgba(#000, 0.12);
    padding: 32px;
    border-radius: $border-radius;
  }

  .cactus-login-field {
    > input {
      border: 0;
      border-bottom: 1px solid;
      background: transparent;
      outline: none;
    }
  }
}