Lawrence  Lesch

Lawrence Lesch

1667916960

Papercups: Open-source Live Customer Chat

Papercups

Papercups is an open source live customer support tool web app written in Elixir. We offer a hosted version at app.papercups.io.

You can check out how our chat widget looks and play around with customizing it on our demo page. The chat widget component is also open sourced at github.com/papercups-io/chat-widget.

Watch how easy it is to get set up with our Slack integration 🚀 : slack-setup

One click Heroku deployment

The fastest way to get started is one click deploy on Heroku with:

Philosophy

We wanted to make a self-hosted customer support tool like Zendesk and Intercom for companies that have privacy and security concerns about having customer data going to third party services.

Features

  • Reply from email - use Papercups to answer support tickets via email
  • Reply from SMS - forward Twilio conversations and respond to SMS requests from Papercups
  • Custom chat widget - a customizable chat widget you can embed on your website to talk to your customers
  • React support - embed the chat widget as a React component, or a simple HTML snippet
  • React Native support - embed the chat widget in your React Native app
  • Flutter support - embed the chat widget in your Flutter app (courtesy of @aguilaair :heart:)
  • Slack integration - connect with Slack, so you can view and reply to messages directly from a Slack channel
  • Mattermost integration - connect with Mattermost, so you can view and reply to messages directly from Mattermost
  • Markdown and emoji support - use markdown and emoji to add character to your messages!
  • Invite your team - send invite links to your teammates to join your account
  • Conversation management - close, assign, and prioritize conversations
  • Built on Elixir - optimized for responsiveness, fault-tolerance, and support for realtime updates

Demo

We set up a simple page that demonstrates how Papercups works.

Try sending us a message to see what the chat experience is like!

Blog

Check out our blog for more updates and learnings

Documentation

Check out our docs at docs.papercups.io

Contributing

We ❤️ contributions big or small. See CONTRIBUTING.md for a guide on how to get started.

⚠️ Maintenance Mode

Papercups is in maintenance mode. This means there won't be any major new features in the near future. We will still accept pull requests and conduct major bug fixes. Read more here

Download Details:

Author: Papercups-io
Source Code: https://github.com/papercups-io/papercups 
License: MIT license

#typescript #javascript #react #heroku #slack #docker 

Papercups: Open-source Live Customer Chat
Monty  Boehm

Monty Boehm

1667617282

Themer Takes A Set Of Colors and Generates Themes for Your Apps

themer 

themer takes a set of colors and generates editor themes, terminal themes, themes for other apps, and desktop/device wallpapers.

visual description

Support themer

Installation

Don't love the command-line? Check out the Web UI.

mkdir my-dotfiles && cd my-dotfiles
npm install themer

If you do not keep your dotfiles under version control, you can simply install themer globally with npm -g install themer.

themer can also be used without installing, via npx—see example below.

Usage

Pass themer a color set, as many templates as you wish, and an output directory.

themer \
  --colors <npm package name OR file> \
  --template <npm package name OR file> \
  [--template <npm package name OR file>...] \
  --out <directory>

Your generated theme files, as well as a README on how to install them, will be written to the output directory.

themer can create themes from your custom color sets (see "Create your own color set" below) or from color sets published on npm (see @themerdev/colors-default). The same is true for templates.

Example workflow

Say you wanted to generate a vim theme and desktop background using themer's default color set. First, install themer, the color set, and the templates:

cd my-dotfiles
npm install themer @themerdev/colors-default @themerdev/vim @themerdev/wallpaper-block-wave

Then edit your package.json:

  ...
  "scripts": {
    "build": "themer -c @themerdev/colors-default -t @themerdev/vim -t @themerdev/wallpaper-block-wave -o gen"
  },
  ...

Then run your new script:

npm run build

Now check the gen/ folder for your generated themes. Here's the result:

example usage result

Example usage with npx

npx \
  -p themer \
  -p @themerdev/colors-default \
  -p @themerdev/vim \
  -p @themerdev/wallpaper-block-wave \
  themer \
  -c @themerdev/colors-default \
  -t @themerdev/vim \
  -t @themerdev/wallpaper-block-wave \
  -o output

Themer color sets

Premium color sets

NameDark PreviewLight Preview
JamstackerJamstacker dark preview(dark only)
Victor MonoVictor Mono dark previewVictor Mono light preview
Future ProFuture Pro dark previewFuture Pro light preview

Original color sets

NameDark PreviewLight Preview
@themerdev/colors-default@themerdev/colors-default dark preview@themerdev/colors-default light preview
@themerdev/colors-finger-paint@themerdev/colors-finger-paint dark preview@themerdev/colors-finger-paint light preview
@themerdev/colors-green-as-a-whistle@themerdev/colors-green-as-a-whistle dark preview@themerdev/colors-green-as-a-whistle light preview
@themerdev/colors-monkey@themerdev/colors-monkey dark preview@themerdev/colors-monkey light preview
@themerdev/colors-night-sky@themerdev/colors-night-sky dark preview(dark only)
@themerdev/colors-polar-ice@themerdev/colors-polar-ice dark preview@themerdev/colors-polar-ice light preview
@themerdev/colors-right-in-the-teals@themerdev/colors-right-in-the-teals dark preview@themerdev/colors-right-in-the-teals light preview

Ports from third-party themes

NameDark PreviewLight Preview
@themerdev/colors-dracula@themerdev/colors-dracula dark preview(dark only)
@themerdev/colors-github-universe!themer/colors-github-universe preview(dark only)
@themerdev/colors-lucid@themerdev/colors-lucid dark preview@themerdev/colors-lucid light preview
@themerdev/colors-mojave@themerdev/colors-mojave dark preview@themerdev/colors-mojave light preview
@themerdev/colors-nova@themerdev/colors-nova preview(dark only)
@themerdev/colors-one@themerdev/colors-one dark preview@themerdev/colors-one light preview
@themerdev/colors-rivet@themerdev/colors-rivet dark preview@themerdev/colors-rivet light preview
@themerdev/colors-seti@themerdev/colors-seti dark preview(dark only)
@themerdev/colors-solarized@themerdev/colors-solarized dark preview@themerdev/colors-solarized light preview

Create your own color set

To create your own color set, create a JavaScript file that exports a colors object, like so:

module.exports.colors = {

  // A color set can have both light and dark variants, but is only required
  // to have one.
  dark: {

    // Colors can be defined in any valid CSS format.

    // accent0-7 should be the main accent colors of your theme. See the table
    // in the "Color mappings" section for how the colors will be used in your
    // new themes.
    accent0: '#FF4050',
    accent1: '#F28144',
    accent2: '#FFD24A',
    accent3: '#A4CC35',
    accent4: '#26C99E',
    accent5: '#66BFFF',
    accent6: '#CC78FA',
    accent7: '#F553BF',

    // shade0-7 should be shades of the same hue, with shade0 being the
    // background and shade7 being the foreground. If you omit the
    // intermediate shades (1 through 6), they will be calculated automatically
    // for you.
    shade0: '#282629',
    shade1: '#474247',
    shade2: '#656066',
    shade3: '#847E85',
    shade4: '#A29DA3',
    shade5: '#C1BCC2',
    shade6: '#E0DCE0',
    shade7: '#FFFCFF'

  },

  // Same as above, except that shade0 should be the lightest and shade7 should
  // be the darkest.
  light: { ... },

};

Pro Tip: you can use themer's Web UI to more easily select your colors, then click the "Download" button to generate a colors.js file.

Then pass the path to your JS file to the --colors argument of themer.

themer -c path/to/my/colors.js ...

Color mappings

To help you choose colors for your own color set, this is approximately how most themer templates will utilize your colors:

Color KeyTypical UsageConventional Color*
accent0error, VCS deletionRed
accent1syntaxOrange
accent2warning, VCS modificationYellow
accent3success, VCS additionGreen
accent4syntaxCyan
accent5syntaxBlue
accent6syntax, caret/cursor 
accent7syntax, specialMagenta
shade0background color 
shade1UI 
shade2UI, text selection 
shade3UI, code comments 
shade4UI 
shade5UI 
shade6foreground text 
shade7foreground text 

*Conventional color is suggested for consistency with ANSI color names in terminal themes, but is not a hard requirement.

See themer's Web UI for a more visual representation of the color mappings.

Tips

  • If you omit shade1 through shade6, themer will interpolate them automatically for you, using color-steps.
  • themer supports any valid CSS color format; that means you can use chartreuse, rgb(127, 255, 0), rgb(50%, 100%, 0%), #7FFF00, hsl(90, 100%, 50%), etc.
  • I would recommend checking your color set into your dotfiles repo. Once you've fine-tuned it, you might consider publishing it to npm for others to use! (If you do, consider naming your package starting with themer-colors- so that others can easily find it.)

Using base16 schemes with Themer

In place of a themer color set file or npm package, you can also provide themer with any base16 scheme YAML file.

themer --colors path/to/base16-scheme.yml ...

Refer to the base16 repository for a list of base16 schemes.

Themer templates

Terminals

Editors/IDEs

Wallpapers

Other

Community

Create your own template

To create your own template, create a JavaScript file that exports a render function, like so:

module.exports.render = function (colors, options) {
  /*

  colors is an object that will have one or both keys: 'light' and
  'dark', each being an object with keys 'accent0' through 'accent7'
  and 'shade0' through 'shade7'.

  options is an object representing the original command-line args
  passed to themer. This allows you to add special arguments that
  will apply only to your template. An example of this is allowing a
  themer user to specify custom resolutions for rendering a wallpaper.

  This function should return an array of Promises, each Promise
  resolving to an object of the following structure:
  {
    name: '<the name of the file to be written>', // can include subdirectories, too
    contents: <a Buffer of the contents of the file to be written>,
  }

  */
};

Your JS file can then be passed to a --template argument of themer. That's it!

Here's an example template render function that generates a Slack sidebar theme from a themer color set.

Once you've developed your template, consider publishing it on npm so that others can use it!

About

themer is inspired by trevordmiller/nova and chriskempson/base16.

Conceptually, themer is very similar to base16, but:

  1. It is lighter, and simpler to use.
  2. It is more easily extensible with your own color sets and templates.
  3. It integrates better with your dotfiles, especially if you keep them under version control.

Contributing

For instructions on how to contribute to themer, see CONTRIBUTING.md and themer's code of conduct.

Themer's Web UI

If you'd prefer to develop your themes visually, check out themer's Web UI, an offline-ready Progressive Web App.

Download Details:

Author: Themerdev
Source Code: https://github.com/themerdev/themer 
License: MIT license

#sketch #atom #vim #theme #slack 

Themer Takes A Set Of Colors and Generates Themes for Your Apps

Lazlo: A Chatops Automation Framework for Slack in Go

Lazlo

An event-driven, lua-scriptable chatops automation framework for Slack in Go. (phew)

The prototypical IRC bot responds to text. Generally, the pattern is you provide a regex to match on, and some code to run when someone says something in chat that matches your regular expression. Your plugin runs when a pattern match happens, and then returns.

Your Lazlo module, by comparison is started at runtime and stays resident in memory. Outwardly, Lazlo acts like a bot, but internally Lazlo works as an event broker. Your module registers for callbacks -- you can tell Lazlo what sorts of events your module finds interesting. For each callback your module registers, Lazlo will hand back a channel. Your module can block on the channel, waiting for something to happen, or it can register more callbacks (as many as you have memory for), and select between them in a loop. Throughout its lifetime, your Module can de-register the callbacks it doesn't need anymore, and ask for new ones as circumstances demand.

Currently there are five different kinds of callbacks you can ask for.

  • Message callbacks specify regex you want to listen for and respond to.
  • Event callbacks specify slack api events you want to listen for and respond to.
  • Timer Callbacks start a (possibly reoccuring) timer (in cron syntax), and notify you when it runs down
  • Link Callbacks create a URL that users can click on. When they do, their GET request is brokered back to your module. (Post and Put support coming soon)
  • Question Callbacks make it easy to ask users a question, and capture their response.

Your module can register for all or none of these, as many times as it likes during the lifetime of the bot. Lazlo makes it easier to write modules that carry out common chat-ops patterns. For example, you can pretty easily write a module that:

  1. registers for a message callback for bot deploy (\w+)
  2. blocks waiting for that command to be executed
  3. when executed, registers for a message callback that matches the specific user that asked for the deploy with the regex: 'authenticate '
  4. DM's that user prompting for a password
  5. registers a timer callback that expires in 3 minutes
  6. Blocks waiting for either the password or the timer
  7. Authenticates the user, and runs the CM tool of the week to perform the deploy
  8. Captures output from that tool and presents it back to the user
  9. de-registers the timer and password callbacks

That's an oversimplified example, but I hope you get the idea. Check out the Modules directory for working examples that use the various callbacks.

Lua plug-ins

Lazlo's event-driven framework is quite flexible. You can use it to write some pretty powerful modules in Go. For example, I implemented a module that embeds a lua state machine which makes it possible to extend Lazlo by write simple plugins that use hubot-like syntax in lua

Whats next?

Current Status

Lazlo is basically working and basically documented. All callback types are implemented and functional and there are several included modules of varying degress of complexity that should help get you started writing your own.

Todo's in order of when I'll probably get to them:

  • Plugin to keep lazlo metadata in synch with Slack
  • Leader-elections for HA bots. (moved up because heroku changing it's dyno pricing)
  • Godoc, Documentation Documentation and Documentation
  • Lua support is new and only includes support for message callbacks (hear respond and reply). I'd like you to be able to get timers and links via lua as well.
  • More included plugins

Download Details:

Author: djosephsen
Source Code: https://github.com/djosephsen/lazlo

License: MIT license

#go #golang #slack 

Lazlo: A Chatops Automation Framework for Slack in Go
Rupert  Beatty

Rupert Beatty

1666603740

Peek: All New Design. inspect Your IOS Application At Runtime

Peek: All new design

Peek 5 with an all new design and all new features. Whether you're a developer, designer or QA/tester, Peek can help you at all stages of your development process.

Watch the Promo to see it in action.

Peek Site

Unified Inspectors

All inspectors and attributes have now been unified into a single window, making inspection simpler and faster than ever before.

Collapsible Groups

Feeling overwhelmed with all the information Peek has to offer? Simply tap the header to expand/collapse any section. Peek will even remember your choice across launches!

Nested Inspectors

Peek now supports nested Inspectors. This powerful feature allows Peek to surface even more detail about your application. In fact Peek 5.0 more than doubles the number of attributes it can inspect.

Previews

Views, images, colours and more can now provide snapshot previews to help you better identify what you’re inspecting.

Reporting

An all new reporting system allows you to export screenshots, metadata and even suggested values using the iOS native share sheet.

Accessibility

Peek itself is now more accessible with Dynamic Type, but Peek can also surface accessibility details from your application.

Search

You can now search within Peek, making it easier than ever to inspect your apps.

Less Code & Dependencies

Thanks to an all new architecture Peek is also now smaller. Providing more features with much less code, leaving a very small footprint on your application.

Ready to get started?

Designers & Testers

  • Simply press one of your volume key(s) to show & hide Peek
  • Now tap or drag your finger across the screen
  • Tap the inspectors button (or double tap anywhere on the screen) to show the Inspectors for the selected view

You can't get simpler than that!

Developers

Device

The simplest way to integrate Peek into your project is to use Cocoapods or Carthage:

# Cocoapods
pod 'Peek', :configurations => ['Debug']

# Carthage
github "shaps80/Peek" ~> 5.1.0

You only need 1 line of code to enable Peek in your application:

window?.peek.enabled = true

Simulator

When running in the Simulator you'll need a couple of extra lines:

// Your AppDelegate
override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
    // iOS 8/9 requires device motion handlers to be on the AppDelegate
    window?.peek.handleShake(motion)
}

or


// Your ViewController
override var canBecomeFirstResponder: Bool {
    return true
}

override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
    // iOS 10 now requires device motion handlers to be on a UIViewController
    UIApplication.shared.keyWindow?.peek.handleShake(motion)
}

Now you can press CMD+CTRL+Z (or use the Menu option) to show/hide Peek in your Simulator.

Contributing

Contributions to Peek are welcomed and encouraged!

It is easy to get involved. Please see the Contributing guide for more details.

A list of contributors is available through GitHub.

To give clarity of what is expected of our community, Peek has adopted the code of conduct defined by the Contributor Covenant. This document is used across many open source communities, and I think it articulates my values well. For more, see the Code of Conduct.

What is Peek?

Peek on Vimeo

Peek is an open source framework that provides runtime inspection of your application while its running on your device (or Simulator).

  • Developers can use Peek to inspect their user interfaces at runtime.
  • Designers can verify that the applications meets their design specifications.
  • Testers and QA can check accessibility identifiers, validate behaviour and report issues.

Peek is a tool to aide you at all stages of your development process.

How does Peek work?

Peek scans your entire user interface on the screen then provides overlays with layout information and attribute inspectors.

Peek includes an intelligent filtering system to best determine which views you care about while ignoring those you are not likely to be interested in.

For example, by default Peek will not show you many of Apple's system components unless they are subclassed.

Peek presents itself in its own window that sits directly on top of your own app's user interface to ensure that it doesn't interfere with normal functionality.

Peek also allows you to test all supported orientations on both iPhone and iPad.

Most importantly Peek doesn’t interfere with your applications logic or user interface in anyway. It provides read-only inspection to guarantee you’re seeing live-values only!

Demo

If you're not ready to integrate Peek into your own project, You can simply download this repo and run the sample project included :)

Its a small app that perfectly demonstrates the power of Peek!

Configuring Peek

Peek allows many options to be configured, allowing you more control over how Peek is configured as well as reporting options:

window?.peek.enableWithOptions { options in
    options.theme = .black
    options.activationMode = .auto
    options.shouldIgnoreContainers = true

    /*
      Sometimes it can also be useful to include additional metadata with each report.
     */
    options.metaData = [ "Environment": "UAT" ]
}

Safety First

Peek is designed to be as safe as possible. Peek will never retain objects from your application. It will never use a background thread. Peek won't even run unless you explicitly enable it!

Go ahead, take a Peek at your app now :)

Supported Platforms and Versions

Peek is officially supported (and tested) with the following configurations:

  • iOS 9.0+ (Swift and Objective-C)

Note: if you're having issues with Swift versions when using Cocoapods, try adding the following to your Podfile:

post_install do |installer|
    installer.pods_project.targets.each do |target|
        if target.name == "Peek" then
            target.build_configurations.each do |config|
                config.build_settings['SWIFT_VERSION'] = '4.0'
            end
        end
    end
end

Swift Versions

Swift 4.x

Currently supported by version Peek v4.0 – v5.0

Swift 3.x

Not officially supported. Its recommended you update to Swift 4 and Peek 5.0

Swift 2.3

If you need Swift 2.3 support, update your Podfile as such:

pod 'Peek', '2.3'

Swift 2.2

If you need Swift 2.2 support, update your Podfile as such:

pod 'Peek', '2.0'


Attribution

Original concept, code and app design by @shaps
 

Icons in the demo app found on The Noun Project. Artwork by Vitaliy Gorbachev

Download Details:

Author: Shaps80
Source Code: https://github.com/shaps80/Peek 
License: MIT license

#swift #ios #slack 

Peek: All New Design. inspect Your IOS Application At Runtime

Slack-term: Slack Client for Your Terminal

Slack-term

A Slack client for your terminal.

Screenshot

Installation

Binary installation

Download a compatible binary for your system. For convenience, place slack-term in a directory where you can access it from the command line. Usually this is /usr/local/bin.

$ mv slack-term /usr/local/bin

Via Go

If you want, you can also get slack-term via Go:

$ go get -u github.com/erroneousboat/slack-term
$ cd $GOPATH/src/github.com/erroneousboat/slack-term
$ go install .

Via docker

You can also run it with docker, make sure you have a valid config file on your host system.

docker run -it -v [config-file]:/config erroneousboat/slack-term

Setup

Get a slack token, click here

Running slack-term for the first time, will create a default config file at ~/.config/slack-term/config.

$ slack-term
  1. Update the config file and update your slack_token For more configuration options of the config file, see the wiki.
{
    "slack_token": "yourslacktokenhere"
}

Usage

When everything is setup correctly you can run slack-term with the following command:

$ slack-term

Default Key Mapping

Below are the default key-mappings for slack-term, you can change them in your config file.

modekeyaction
commandiinsert mode
command/search mode
commandkmove channel cursor up
commandjmove channel cursor down
commandgmove channel cursor top
commandGmove channel cursor bottom
commandKthread up
commandJthread down
commandGmove channel cursor bottom
commandpg-upscroll chat pane up
commandctrl-bscroll chat pane up
commandctrl-uscroll chat pane up
commandpg-downscroll chat pane down
commandctrl-fscroll chat pane down
commandctrl-dscroll chat pane down
commandnnext search match
commandNprevious search match
command,jump to next notification
commandqquit
commandf1help
insertleftmove input cursor left
insertrightmove input cursor right
insertentersend message
insertesccommand mode
searchesccommand mode
searchentercommand mode

Download Details:

Author: jpbruinsslot
Source Code: https://github.com/jpbruinsslot/slack-term 
License: MIT license

#go #golang #slack #terms #cli 

Slack-term: Slack Client for Your Terminal
Python  Library

Python Library

1662011460

Slack Templates: Send informative, Concise Slack Notifications

slack-templates

Send Informative, Concise Slack Notifications With Minimal Effort

Slack Integration

  • Create a custom Slack app with the chat:write scope.
  • Install the app to your workspace, and copy the provided OAuth access token.
  • Create a GitHub secret to store the bot token.
  • Invite your bot to the desired channel.
  • Secondary-click on the channel, and select "Copy link."
  • Create a GitHub secret to store the final portion of the path. The channel ID is neither the name of the channel nor the URL.

Available Templates

The template parameter controls the structure of the Slack notification. Here are all currently supported templates:

  • "result":
    • pull_request event: <workflow> <result> for <PR #> from <branch> on <repository> by <username>.
    • push event:
      • merge of pull request: <workflow> <result> for merge of <PR #> to <branch> on <repository> by <username>.
      • direct push of branch: <workflow> <result> for push of <sha> to <branch> on <repository> by <username>.
  • "reviewers":
    • requestor != requestee: <requestor> requests review from <reviewers> of <PR #> from <branch> on <repository>.
    • requestor == requestee: <username> self-requests review of <PR #> from <branch> on <repository>.
  • "assignee":
    • assignor != assignee: <assignor> assigned <assignee> <PR #> from <branch> on <repository>.
    • assignor == assignee: <username> self-assigned <PR #> from <branch> on <repository>.
  • "custom": Pass your custom message via the message parameter.

All usernames refer to GitHub usernames. Users with differing Slack and GitHub usernames may wish to register their GitHub username for Slack keyword notifications. Workflow names, pull request numbers, commit shas, branches, and repositories all link to the pertinent GitHub page. If you would like to see a template added, please open an issue or better still a pull request.

Reliably determining the pull request associated with a push event requires read permissions on the contents scope. Even the restrictive defaults grant this permission. If permissions are granted explicitly and contents: read is excluded, the commit sha will be reported instead of the pull request number, because merges will be indistinguishable from direct pushes.

Usage

Report the status of the current job

  • Add the following step to the bottom of the job:
- name: Send Slack notification with job status.
  if: always()
  uses: ScribeMD/slack-templates@0.6.7
  with:
    bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
    channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
    template: result

Summarize the results of an entire workflow

  • Create a new job at the end of the workflow that depends on (a.k.a., "needs") all other jobs but always runs.
  • Pass "${{ join(needs.*.result, ' ') }}" as the results.

The result of the entire workflow is the highest ranking of all results given. The ranking is as follows:

  1. failure
  2. cancelled
  3. success
  4. skipped
name: My Workflow
on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main
jobs:
  job1: ...
  job2: ...
  job3: ...
  notify:
    if: always()
    needs:
      - job1
      - job2
      - job3
    runs-on: ubuntu-latest
    steps:
      - name: Send Slack notification with workflow result.
        uses: ScribeMD/slack-templates@0.6.7
        with:
          bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
          channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
          template: result
          results: "${{ join(needs.*.result, ' ') }}"

Report a custom result

  • Determine what result to send in preceding steps.
  • Report the result at the bottom of the job as before.
  • Take care to quote results for use as a Bash command line argument.
- name: Detect third-party network outage.
  id: network
  run: |
    ...
    echo "::set-output name=outage::$OUTAGE"
  shell: bash
- name: Send Slack notification with custom result.
  if: always() && steps.network.outputs.outage == 'true'
  uses: ScribeMD/slack-templates@0.6.7
  with:
    bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
    channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
    template: result
    results: '"failure caused by third-party network outage"'

Notify reviewers of a pull request

name: Notify Reviewers
on:
  pull_request:
    types:
      - review_requested
jobs:
  notify-reviewers:
    runs-on: ubuntu-latest
    steps:
      - name: Send Slack notification requesting code review.
        uses: ScribeMD/slack-templates@0.6.7
        with:
          bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
          channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
          template: reviewers

Notify assignee of a pull request

name: Notify Assignee
on:
  pull_request:
    types:
      - assigned
jobs:
  notify-assignee:
    runs-on: ubuntu-latest
    steps:
      - name: Send Slack notification assigning pull request.
        uses: ScribeMD/slack-templates@0.6.7
        with:
          bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
          channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
          template: assignee

Send a custom notification

- name: Send custom Slack notification.
  if: always()
  uses: ScribeMD/slack-templates@0.6.7
  with:
    bot-token: ${{ secrets.SLACK_TEMPLATES_BOT_TOKEN }}
    channel-id: ${{ secrets.SLACK_TEMPLATES_CHANNEL_ID }}
    message: "${{ github.actor }} requests approval to run workflow."

Inputs

Required

bot-token

The Slack API bot token for your custom app with chat:write scope.

channel-id

The ID of a Slack channel to send notifications to. Your bot should be a member. Secondary-click on the channel in Slack, and select Copy link to copy a URL containing the channel ID.

Optional

template

default: custom

The type of Slack notification to send:

  • assignee
  • custom (requires message)
  • reviewers
  • result

results (template: result only)

default: ${{ job.status }}

The job results to report via Slack. To report the result of an entire workflow, use this action from a final notify job that depends on (a.k.a., needs) all other jobs. Then, pass join(needs.*.result, ' '). The highest ranking result will be reported:

  1. failure
  2. cancelled
  3. success
  4. skipped

Alternatively, a custom result may be passed provided that it is quoted for use as a Bash command line argument.

message (template: custom only)

default: Pass message or template to slack-templates.

A custom Slack message to send.

Relation to slack-send

This action wraps slack-send, its only runtime dependency, inheriting slack-send's support for all GitHub-hosted runners. There are three principal differences between these actions:

  • slack-templates offers some default messages; slack-send presently does not.
  • slack-send supports Slack's Workflow Builder (unavailable on free Slack plan) in addition to Slack apps. slack-templates only supports Slack apps.
  • slack-send accepts the bot token as environment variable SLACK_BOT_TOKEN. slack-templates accepts it as the input parameter bot-token.

Bug Reports

If you are not receiving notifications, please review the Slack Integration section and then file a bug report containing the GitHub Action's logs if that doesn't resolve your issue. If you are receiving nondescript Slack notifications, please file a bug report with the notification you received taking care to preserve the links.

Permissions

The contents:read and pull-requests:read permissions are required in private repositories to determine the pull request associated with a push event since the push event itself doesn't contain this information.

Download details:

Author: ScribeMD
Source code:  https://github.com/ScribeMD/slack-templates 
License: MIT license 

#python #slack

Slack Templates: Send informative, Concise Slack Notifications

Slack Clone: Clone Of A Slack Deployed using React and Firebase

About The Project

Slack Clone

Description

  • Slack-Clone is a clone of a slack. Implemented using React and Firebase.
  • Behind the backend, I was used React-Firebase for authentication with Google-auth, and highly secure specially for non-authorized users.
  • And I have developed a channel section to add new channels and communicate through these channels.
  • I have used firestore to keep store all the messages spread among the channels or community.
  • And ofcourse our database will be safe under google-firebase security so no worries about securities.

Features

  • The channels or messages are stored in firestore database so quickly accessible via our app.
  • I was used react-router-dom for saving server-side loads or refreshing. this functionality improve the speed for redirect to one component to another without refreshing from server-side it makes life easier, save lots of time and fast to switch without loading or refreshing the whole page.
  • Our data will be in real-time, if any changes make happens in messages or channels then it will automatically changes in our app in real-time no need to refresh our page. the app will be responsive like if you used in Desktop or Mobile devices it render same thing.

Built With

This section should list any major frameworks that you built your project using. Leave any add-ons/plugins for the acknowledgements section. Here are a few examples.

Getting Started with Create React App

This project was bootstrapped with Create React App.

Available Scripts

In the project directory, you can run:

npm start

Runs the app in the development mode.\

Open http://localhost:3000 to view it in your browser.

The page will reload when you make changes.
You may also see any lint errors in the console.

npm test

Launches the test runner in the interactive watch mode.
See the section about running tests for more information.

npm run build

Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

See the section about deployment for more information.

npm run eject

Note: this is a one-way operation. Once you eject, you can't go back!

If you aren't satisfied with the build tool and configuration choices, you can eject at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.

You don't have to ever use eject. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

Learn More

You can learn more in the Create React App documentation.

To learn React, check out the React documentation.

Code Splitting

This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting

Analyzing the Bundle Size

This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size

Making a Progressive Web App

This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app

Advanced Configuration

This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration

Deployment

This section has moved here: https://facebook.github.io/create-react-app/docs/deployment

npm run build fails to minify

This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify


Author: MuradRahmanzada
Source code: https://github.com/MuradRahmanzada/Slack-clone
 

#react-native #javascript #Firebase #slack 

Slack Clone: Clone Of A Slack Deployed using React and Firebase
Royce  Reinger

Royce Reinger

1658466420

Slack-ruby-gem: A Ruby Wrapper for The Slack API

Slack

A Ruby wrapper for the Slack API

Installation

Add this line to your application's Gemfile:

gem 'slack-api'

And then execute:

$ bundle

Or install it yourself as:

$ gem install slack-api

Usage

require "slack"

Slack.configure do |config|
  config.token = "YOUR_TOKEN"
end

Slack.auth_test

Documentation

http://www.rubydoc.info/gems/slack-api

Examples

https://github.com/aki017/slack-ruby-gem/tree/dev/examples

Contributing

  1. Fork it ( http://github.com/aki017/slack-ruby-gem/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Author: aki017
Source Code: https://github.com/aki017/slack-ruby-gem 
License: MIT license

#ruby #slack #api 

Slack-ruby-gem: A Ruby Wrapper for The Slack API
Royce  Reinger

Royce Reinger

1658458920

Ruby, Command-line Client for The Slack Web, Real Time Messaging APIs

Slack Ruby Client  

A Ruby client for the Slack Web, RealTime Messaging and Events APIs. Comes with a handy command-line client, too. If you are not familiar with these concepts, you might want to watch this video.

Useful to Me?

  • This library will let you send messages to Slack via the Web API, send and receive messages via the Real Time Messaging API and facilitate integration with the Events API.
  • To respond to slash commands, interactive components or events, implement a web application using your favorite web framework and use this library to call the Slack Web API and to verify that events are coming from Slack.
  • To build a bot using the Real Time Messaging API, use slack-ruby-bot, which uses this library.
  • To roll out a complete service using the Real Time Messaging API with Slack button integration to multiple teams, check out slack-ruby-bot-server, which is built on top of slack-ruby-bot, which uses this library.

Stable Release

You're reading the documentation for the next release of slack-ruby-client. Please see the documentation for the last stable release, v1.0.0 unless you're integrating with HEAD. See UPGRADING when upgrading from an older version.

Installation

Add to Gemfile.

gem 'slack-ruby-client'

If you're going to be using the RealTime client, add async-websocket. See below for more information about concurrency.

gem 'async-websocket', '~> 0.8.0'

Run bundle install.

Usage

Create a New Bot Integration

To integrate your bot with Slack, you must first create a new Slack App.

OAuth Code Grant

Once created, go to the app's Basic Info tab and grab the Client ID and Client Secret. You'll need these in order complete an OAuth code grant flow as described at slack-ruby-bot-server.

Using the Legacy API Token

Although OAuth is recommended, you can still generate a legacy API token for your app and use it for some interactions.

Slack.configure do |config|
  config.token = ENV['SLACK_API_TOKEN']
end

This sets a global default token. You can also pass a token into the initializer of both Slack::Web::Client and Slack::RealTime::Client or configure those separately via Slack::Web::Config.configure and Slack::RealTime::Config.configure. The instance token will be used over the client type token over the global default.

Global Settings

The following global settings are supported via Slack.configure.

settingdescription
tokenSlack API token.
loggerAn optional logger, defaults to ::Logger.new(STDOUT) at Logger::WARN level.

Web Client

The Slack Web API allows you to build applications that interact with Slack.

Web Client Examples

Here are some examples of how to use the web client with the Web API.

Test Auth

client = Slack::Web::Client.new
client.auth_test

Send Messages

Send messages with chat_PostMessage.

client.chat_postMessage(channel: '#general', text: 'Hello World', as_user: true)

See a fully working example in examples/hi_web.

hi.gif

List Channels

List channels with conversations_list.

channels = client.conversations_list.channels

general_channel = channels.detect { |c| c.name == 'general' }

Upload a File

Upload a file with files_upload.

client.files_upload(
  channels: '#general',
  as_user: true,
  file: Faraday::UploadIO.new('/path/to/avatar.jpg', 'image/jpeg'),
  title: 'My Avatar',
  filename: 'avatar.jpg',
  initial_comment: 'Attached a selfie.'
)

Get Channel Info

You can use a channel ID or name (prefixed with #) in all functions that take a :channel argument. Lookup by name is not supported by the Slack API and the channels_id method called invokes conversations_list in order to locate the channel ID.

client.conversations_info(channel: 'C04KB5X4D') # calls conversations_info
client.conversations_info(channel: '#general') # calls conversations_list followed by conversations_info

Get User Info

You can use a user ID or name (prefixed with @) in all functions that take a :user argument. Lookup by name is not supported by the Slack API and the users_id method called invokes users_list in order to locate the user ID.

client.users_info(user: 'U092BDCLV') # calls users_info
client.users_info(user: '@dblock') # calls users_list followed by users_info

Search for a User

Constructs an in-memory index of users and searches it. If you want to use this functionality, add the picky gem to your project's Gemfile.

client.users_search(user: 'dblock')

Other

Refer to the Slack Web API Method Reference for the list of all available functions.

Web Client Options

You can configure the Web client either globally or via the initializer.

Slack::Web::Client.configure do |config|
  config.user_agent = 'Slack Ruby Client/1.0'
end
client = Slack::Web::Client.new(user_agent: 'Slack Ruby Client/1.0')

The following settings are supported.

settingdescription
tokenSlack API token.
user_agentUser-agent, defaults to Slack Ruby Client/version.
proxyOptional HTTP proxy.
ca_pathOptional SSL certificates path.
ca_fileOptional SSL certificates file.
endpointSlack endpoint, default is https://slack.com/api.
loggerOptional Logger instance that logs HTTP requests.
timeoutOptional open/read timeout in seconds.
open_timeoutOptional connection open timeout in seconds.
default_page_sizeOptional page size for paginated requests, default is 100.
default_max_retriesOptional number of retries for paginated requests, default is 100.
adapterOptional HTTP adapter to use, defaults to Faraday.default_adapter.

You can also pass request options, including timeout and open_timeout into individual calls.

client.conversations_list(request: { timeout: 180 })

You can also control what proxy options are used by modifying the http_proxy environment variable per Net::HTTP's documentation.

Note that Docker on OSX seems to incorrectly set the proxy, causing Faraday::ConnectionFailed, ERROR -- : Failed to open TCP connection to : (getaddrinfo: Name or service not known). You might need to manually unset http_proxy in that case, eg. http_proxy="" bundle exec ruby ./my_bot.rb.

Pagination Support

The Web client natively supports cursor pagination for methods that allow it, such as users_list. Supply a block and the client will make repeated requests adjusting the value of cursor with every response. The default limit is set to 100 and can be adjusted via Slack::Web::Client.config.default_page_size or by passing it directly into the API call.

all_members = []
client.users_list(presence: true, limit: 10) do |response|
  all_members.concat(response.members)
end
all_members # many thousands of team members retrieved 10 at a time

When using cursor pagination the client will automatically pause and then retry the request if it runs into Slack rate limiting. (It will pause according to the Retry-After header in the 429 response before retrying the request.) If it receives too many rate-limited responses in a row it will give up and raise an error. The default number of retries is 100 and can be adjusted via Slack::Web::Client.config.default_max_retries or by passing it directly into the method as max_retries.

You can also proactively avoid rate limiting by adding a pause between every paginated request with the sleep_interval parameter, which is given in seconds.

all_members = []
client.users_list(presence: true, limit: 10, sleep_interval: 5, max_retries: 20) do |response|
  # pauses for 5 seconds between each request
  # gives up after 20 consecutive rate-limited responses
  all_members.concat(response.members)
end
all_members # many thousands of team members retrieved 10 at a time

Character Encoding

Note that Slack expects text to be UTF-8 encoded. If your messages appear with text such as BAD+11 in Slack, check text.encoding and .encode(Encoding::UTF_8) your messages before sending them to Slack.

text = 'characters such as "Ñ", "Á", "É"'
text.encoding
=> #<Encoding:UTF-8>
client.chat_postMessage(channel: '#general', text: text, as_user: true)
# renders 'characters such as "Ñ", "Á", "É"' in Slack

text = text.encode(Encoding::ISO_8859_1)
text.encoding
# => #<Encoding:ISO-8859-1>
client.chat_postMessage(channel: '#general', text: text, as_user: true)
# renders 'characters such as "BAD+11", "", "BAD+9"' in Slack

Error Handling

Slack Errors

If Slack returns an error for the request, then an error will be raised. The error class is specific to the type of error that Slack returns. For instance if Slack returns account_inactive then the error will be Slack::Web::Api::Errors::AccountInactive. This allows you to handle certain types of errors as needed:

rescue Slack::Web::Api::Errors::AccountInactive => e
  # deal with inactive account
end

All of these errors inherit from Slack::Web::Api::Errors::SlackError, so you can handle or silence all errors if necessary:

rescue Slack::Web::Api::Errors::SlackError => e
  # capture all Slack errors
end

If there's a new error type that is not yet known by this library, then it will raise Slack::Web::Api::Errors::SlackError. (Update the Web API if you find that errors are missing — see CONTRIBUTING.)

In all of these cases the error message contains the error code, which is also accessible with slack_error.error. In case of multiple errors, the error message contains the error codes separated by commas, or they are accessible as an array with slack_error.errors. The original response is also accessible using the response attribute. The response_metadata is accessible with slack_error.response_metadata.

Rate Limiting

If you exceed Slack’s rate limits, a Slack::Web::Api::Errors::TooManyRequestsError will be raised instead. (This does not inherit from Slack::Web::Api::Errors::SlackError.)

Other Errors

When Slack is temporarily unavailable a subclass of Slack::Web::Api::Errors::ServerError will be raised and the original Faraday::Error will be accesible via exception.cause. (Starting with 0.18.0 this is no longer a subclass of Slack::Web::Api::Errors::SlackError.)

Specifically Slack::Web::Api::Errors::ParsingError will be raised on non-json response (i.e. 200 OK with Slack unavailable HTML page) and Slack::Web::Api::Errors::HttpRequestError subclasses for connection failures (Slack::Web::Api::Errors::TimeoutError for read/open timeouts & Slack::Web::Api::Errors::UnavailableError for 5xx HTTP responses).

In any other case, a Faraday::ClientError will be raised.

RealTime Client

The Real Time Messaging API is a WebSocket-based API that allows you to receive events from Slack in real time and send messages as user.

client = Slack::RealTime::Client.new

client.on :hello do
  puts "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com."
end

client.on :message do |data|
  case data.text
  when 'bot hi' then
    client.message(channel: data.channel, text: "Hi <@#{data.user}>!")
  when /^bot/ then
    client.message(channel: data.channel, text: "Sorry <@#{data.user}>, what?")
  end
end

client.on :close do |_data|
  puts "Client is about to disconnect"
end

client.on :closed do |_data|
  puts "Client has disconnected successfully!"
end

client.start!

You can send typing indicators with typing.

client.typing channel: data.channel

You can send a ping with ping.

client.ping

By default, the RealTime client exposes and maintains a local store with the properties of rtm.start upon a successful connection.

propertydescription
urlA WebSocket Message Server URL.
selfThe authenticated bot user.
teamDetails on the authenticated user's team.
usersA hash of user objects by user ID.
channelsA hash of channel objects, one for every channel visible to the authenticated user.
groupsA hash of group objects, one for every group the authenticated user is in.
imsA hash of IM objects, one for every direct message channel visible to the authenticated user.
botsDetails of the integrations set up on this team.

It also tracks changes, such as users being renamed, added or deleted, therefore client.users is always up-to-date.

Tracking with a local store can be disabled with Slack::RealTime::Client.new(store_class: nil). Other stores are also available.

Slack::RealTime::Stores::Store

The default store that tracks all changes. By default the client will be connected using rtm_start.

Slack::RealTime::Stores::Starter

A smaller store that only stores and tracks information about the bot user, but not channels, users, groups, ims or bots. By default the client will be connected using rtm_connect.

Configuring Slack::RealTime::Client

You can configure the RealTime client either globally or via the initializer.

Slack::RealTime::Client.configure do |config|
  config.websocket_ping = 42
end
client = Slack::RealTime::Client.new(websocket_ping: 42)

The following settings are supported.

settingdescription
tokenSlack API token.
websocket_pingHow long the socket can be idle before sending a ping message to confirm it's still connected, default is 30.
websocket_proxyConnect via proxy, include :origin and :headers.
store_classLocal store class name, default is an in-memory Slack::RealTime::Stores::Store.
start_methodOptional start method, either :rtm_start or :rtm_connect.
start_optionsOptions to pass into rtm.start or rtm.connect, default is { request: { timeout: 180 } }.
loggerOptional Logger instance that logs RealTime requests and socket data.

Note that the RealTime client uses a Web client to obtain the WebSocket URL via rtm.start or rtm.connect. While token and logger options are passed down from the RealTime client, you may also configure Web client options via Slack::Web::Client.configure as described above.

See a fully working example in examples/hi_real_time.

Caveats

websocket_ping

This setting determines how long the socket can be idle before sending a ping message to confirm it's still connected.

It's important to note that if a ping message was sent and no response was received within the amount of time specified in websocket_ping the client will attempt to reestablish it's connection to the message server.

Note that the ping may take between websocket_ping and websocket_ping * 3/2 seconds to actually trigger when there is no activity on the socket. This is because the timer that checks whether to ping is triggered at every websocket_ping / 2 interval.

To disable this feature set websocket_ping to 0.

Connection Methods

The RealTime client uses either rtm.start or rtm.connect to open a connection. The former retrieves a lot of team information while the latter only serves connection purposes and is preferred. You should let the library choose the right method for you based on the store_class used and override this behavior with start_method when necessary.

Slack::RealTime::Client.configure do |config|
  config.start_method = :rtm_start
end

Combining RealTime and Web Clients

Since the Web client is used to obtain the RealTime client's WebSocket URL, you can continue using the Web client in combination with the RealTime client.

client = Slack::RealTime::Client.new

client.on :message do |data|
  case data.text
  when 'bot hi' then
    client.web_client.chat_postMessage(channel: data.channel, text: "Hi <@#{data.user}>!")
  when /^bot/ then
    client.web_client.chat_postMessage(channel: data.channel, text: "Sorry <@#{data.user}>, what?")
  end
end

client.start!

See a fully working example in examples/hi_real_time_and_web.

hi.gif

Large Team Considerations

The rtm.start call downloads a large amount of data. For large teams, consider reducing the amount of unnecessary data downloaded with start_options. You may also want to increase the default timeout of 180 seconds.

Slack::RealTime::Client.configure do |config|
  # Return timestamp only for latest message object of each channel.
  config.start_options[:simple_latest] = true
  # Skip unread counts for each channel.
  config.start_options[:no_unreads] = true
  # Increase request timeout to 6 minutes.
  config.start_options[:request][:timeout] = 360
end

See #134 for a discussion on this topic.

Concurrency

Slack::RealTime::Client needs help from a concurrency library and supports Async.

Slack::RealTime.configure do |config|
  config.concurrency = Slack::RealTime::Concurrency::Async
end

Use client.start_async instead of client.start!. A good example of such application is slack-ruby-bot-server.

client = Slack::RealTime::Client.new

client.start_async

Async

Add async-websocket to your Gemfile.

gem 'async-websocket'

See a fully working example in examples/hi_real_time_async_async.

Events API

This library provides limited support for the Slack Events API.

Configuring Slack::Events

You can configure Events support globally.

Slack::Events.configure do |config|
  config.signing_secret = 'secret'
end

The following settings are supported.

settingdescription
signing_secretSlack signing secret, defaults is ENV['SLACK_SIGNING_SECRET'].
signature_expires_inSignature expiration window in seconds, default is 300.

Verifying the Request Signature

Slack signs its requests using a secret that's unique to your app. Verify incoming HTTP requests as follows.

slack_request = Slack::Events::Request.new(http_request)
slack_request.verify!

To specify secrets on a per-request basis:

Slack::Events::Request.new(http_request,
                           signing_secret: signing_secret,
                           signature_expires_in: signature_expires_in)

The verify! call may raise Slack::Events::Request::MissingSigningSecret, Slack::Events::Request::InvalidSignature or Slack::Events::Request::TimestampExpired errors.

Message Parsing

All text in Slack uses the same system of escaping: chat messages, direct messages, file comments, etc. Use Slack::Messages::Formatting to unescape incoming messages. This comes handy, for example, you want to treat all input to a real time bot as plain text.

Slack::Messages::Formatting.unescape('Hello &amp; &lt;world&gt;'))
  # => 'Hello & <world>'
Slack::Messages::Formatting.unescape('Hey <@U024BE7LH|bob>, did you see my file?'))
  # => 'Hey @bob, did you see my file?'
Slack::Messages::Formatting.unescape('Hey <@U02BEFY4U>'))
  # => 'Hey @U02BEFY4U'
Slack::Messages::Formatting.unescape('This message contains a URL <http://foo.com/>'))
  # => 'This message contains a URL http://foo.com/'
Slack::Messages::Formatting.unescape('So does this one: <http://www.foo.com|www.foo.com>'))
  # => 'So does this one: www.foo.com'
Slack::Messages::Formatting.unescape('<mailto:bob@example.com|Bob>'))
  # => 'Bob'
Slack::Messages::Formatting.unescape('Hello <@U123|bob>, say hi to <!everyone> in <#C1234|general>'))
  # => 'Hello @bob, say hi to @everyone in #general'
Slack::Messages::Formatting.unescape('Hello <@U123|bob> &gt; file.txt'))
  # => 'Hello @bob > file.txt'
Slack::Messages::Formatting.unescape('“hello”'))
  # => '"hello"'
Slack::Messages::Formatting.unescape('‘hello’'))
  # => "'hello'"

Command-Line Client

The slack command-line client returns JSON data from the Slack API.

Authenticate with Slack

$ slack --slack-api-token=[token] auth test
{"ok":true,"url":"...","team":"...","user":"...","team_id":"...","user_id":"..."}

Send a Message

export SLACK_API_TOKEN=...
$ slack chat postMessage --text="hello world" --channel="#general"
{"ok":true,"channel":"...","ts":"...","message":{"text":"hello world","username":"bot","type":"message","subtype":"bot_message","ts":"..."}}

Get Channel Id

$ slack channels id --channel=#general
{"ok":true,"channel":{"id":"C04KB5X4D"}}

Get Channel Info

$ slack channels info --channel=#general
{"ok":true,"channel":{"id":"C04KB5X4D","name":"general", ...}}

List Users

Combine with jq, a command-line JSON parser.

$ slack users list | jq '.members | map({(.id): .name})'
[
  {
    "U04KB5WQR": "dblock"
  },
  {
    "U07518DTL": "rubybot"
  }
]

See slack help for a complete command-line reference.

History

This gem is based on slack-ruby-gem, but it more clearly separates the Web and RTM APIs, is more thoroughly tested and is in active development.

Contributing

See CONTRIBUTING.

Author: dblock
Source Code: https://github.com/dblock/slack-ruby-client 
License: MIT license

#ruby #client #slack 

Ruby, Command-line Client for The Slack Web, Real Time Messaging APIs
Royce  Reinger

Royce Reinger

1658454960

Slack-ruby-bot: The Easiest Way to Write A Slack Bot in Ruby

Slack-Ruby-Bot 

A generic Slack bot framework written in Ruby on top of slack-ruby-client. This library does all the heavy lifting, such as message parsing, so you can focus on implementing slack bot commands. It also attempts to introduce the bare minimum number of requirements or any sorts of limitations. It's a Slack bot boilerplate.

Useful to Me?

  • If you are just trying to send messages to Slack, use slack-ruby-client, which this library is built on top of.
  • If you're trying to roll out a full service with Slack button integration, check out slack-ruby-bot-server, which uses this library.
  • Otherwise, this piece of the puzzle will help you create a single bot instance for one team.

Stable Release

You're reading the documentation for the next release of slack-ruby-bot. Please see the documentation for the last stable release, v0.12.0 unless you're integrating with HEAD. See CHANGELOG for a history of changes and UPGRADING for how to upgrade to more recent versions.

Usage

A Minimal Bot

Gemfile

source 'https://rubygems.org'

gem 'slack-ruby-bot'
gem 'async-websocket', '~>0.8.0'

pongbot.rb

require 'slack-ruby-bot'

class PongBot < SlackRubyBot::Bot
  command 'ping' do |client, data, match|
    client.say(text: 'pong', channel: data.channel)
  end
end

PongBot.run

After registering the bot, run with SLACK_API_TOKEN=... bundle exec ruby pongbot.rb. Have the bot join a channel and send it a ping.

demo.gif

A Production Bot

A typical production Slack bot is a combination of a vanilla web server and a websocket application that talks to the Slack Real Time Messaging API. See our Writing a Production Bot tutorial for more information.

More Involved Examples

The following examples of bots based on slack-ruby-bot are listed in growing order of complexity.

Commands and Operators

Bots are addressed by name, they respond to commands and operators. You can combine multiple commands.

class CallBot < SlackRubyBot::Bot
  command 'call', '呼び出し' do |client, data, match|
    client.say(channel: data.channel, text: 'called')
  end
end

Command match data includes match['bot'], match['command'] and match['expression']. The bot match always checks against the SlackRubyBot::Config.user and SlackRubyBot::Config.user_id values obtained when the bot starts.

The command method can take strings, which will have to be escaped with Regexp.escape, and regular expressions.

class CallBot < SlackRubyBot::Bot
  command 'string with spaces', /some\s*regex+\?*/ do |client, data, match|
    client.say(channel: data.channel, text: match['command'])
  end
end

Operators are 1-letter long and are similar to commands. They don't require addressing a bot nor separating an operator from its arguments. The following class responds to =2+2.

class MathBot < SlackRubyBot::Bot
  operator '=' do |client, data, match|
    # implementation detail
  end
end

Operator match data includes match['operator'] and match['expression']. The bot match always checks against the SlackRubyBot::Config.user setting.

Threaded Messages

To reply to a message in a thread you must provide a reference to the first message that initiated the thread, which is available as either data.ts if no threaded messages have been sent, or data.thread_ts if the message being replied to is already in a thread. See message-threading for more information.

command 'reply in thread' do |client, data, match|
  client.say(
    channel: data.channel,
    text: "let's avoid spamming everyone, I will tell you what you need in this thread",
    thread_ts: data.thread_ts || data.ts
  )
end

Note that sending a message using only thread_ts: data.ts can cause some permanent issues where Slack will keep reporting inaccessible messages as unread. At the time of writing the slack team is still having problems clearing those notifications. As recommended by the slack documentation ...

A true parent's thread_ts should be used when replying. Providing a child's message ID will result in a new, detached thread breaking all context and sense.

... the replies to a thread should always be sent to the message ts that started the thread, available as thread_ts for subsequent messages. Hence data.thread_ts || data.ts.

For additional options, including broadcasting, see slack-ruby-client#chat_postMessage.

Bot Aliases

A bot will always respond to its name (eg. rubybot) and Slack ID (eg. @rubybot), but you can specify multiple aliases via the SLACK_RUBY_BOT_ALIASES environment variable or via an explicit configuration.

SLACK_RUBY_BOT_ALIASES=:pp: table-tennis
SlackRubyBot.configure do |config|
  config.aliases = [':pong:', 'pongbot']
end

This is particularly fun with emoji.

aliases.gif

Bots will also respond to a direct message, with or without the bot name in the message itself.

dms.gif

Generic Routing

Commands and operators are generic versions of bot routes. You can respond to just about anything by defining a custom route.

class Weather < SlackRubyBot::Bot
  match /^How is the weather in (?<location>\w*)\?$/ do |client, data, match|
    client.say(channel: data.channel, text: "The weather in #{match[:location]} is nice.")
  end
end
weather.gif

You can also capture multiple matchers with scan.

class Market < SlackRubyBot::Bot
  scan(/([A-Z]{2,5})/) do |client, data, stocks|
    # lookup stock market price
  end
end
market.gif

See examples/market for a working example.

Matching text in message attachments

You can respond to text in attachments with attachment. It will scan text, pretext and title fields in each attachment until a first match is found.

For example you can match this example attachment by its title with the following bot:

class Attachment < SlackRubyBot::Bot
  attachment 'Slack API Documentation' do |client, data, match|
    client.say(channel: data.channel, text: "Matched by #{match.attachment_field}.")
    client.say(channel: data.channel, text: "The attachment's text: #{match.attachment.text}.")
  end
end

You can also define which fields in attachment object should be scanned.

Scan only a single field:

class Attachment < SlackRubyBot::Bot
  attachment 'Slack API Documentation', :title do |client, data, match|
    # implementation details
  end
end

Scan multiple fields:

class Attachment < SlackRubyBot::Bot
  attachment 'Slack API Documentation', %i[text pretext author_name] do |client, data, match|
    # implementation details
  end
end

Providing description for your bot and commands

You can specify help information for bot or commands with help block, for example:

in case of bot:

class WeatherBot < SlackRubyBot::Bot
  help do
    title 'Weather Bot'
    desc 'This bot tells you the weather.'

    command 'clouds' do
      desc 'Tells you how many clouds there\'re above you.'
    end

    command 'What\'s the weather in <city>?' do
      desc 'Tells you the weather in a <city>.'
      long_desc "Accurate 10 Day Weather Forecasts for thousands of places around the World.\n" \
        'Bot provides detailed Weather Forecasts over a 10 day period updated four times a day.'
    end
  end

  # commands implementation
end

in case of your own command:

class Deploy < SlackRubyBot::Commands::Base
  help do
    title 'deploy'
    desc 'deploys your app'
    long_desc 'command format: *deploy <branch> to <env>* where <env> is production or staging'
  end
end

Customize your command help output

If you've used the help block described above to document your commands, you can provide your own implementation of outputting help for commands like so:

class Market < SlackRubyBot::Bot
  command 'help' do |client, data, match|
    user_command = match[:expression]
    help_attrs = SlackRubyBot::Commands::Support::Help.instance.find_command_help_attrs(user_command)
    client.say(channel: data.channel, text: "#{help_attrs.command_desc}\n\n#{help_attrs.command_long_desc}")
  end
end

SlackRubyBot::Commands::Base

The SlackRubyBot::Bot class is DSL sugar deriving from SlackRubyBot::Commands::Base. For more involved bots you can organize the bot implementation into subclasses of SlackRubyBot::Commands::Base manually. By default a command class responds, case-insensitively, to its name. A class called Phone that inherits from SlackRubyBot::Commands::Base responds to phone and Phone and calls the call method when implemented.

class Phone < SlackRubyBot::Commands::Base
  command 'call'

  def self.call(client, data, match)
    client.say(channel: data.channel, text: 'called')
  end
end

To respond to custom commands and to disable automatic class name matching, use the command keyword. The following command responds to call and 呼び出し (call in Japanese).

class Phone < SlackRubyBot::Commands::Base
  command 'call'
  command '呼び出し'

  def self.call(client, data, match)
    client.say(channel: data.channel, text: 'called')
  end
end

Authorization

The framework does not provide any user authentication or command authorization capability out of the box. However, the SlackRubyBot::Commands::Base class does check every command invocation for permission prior to executing the command. The default method always returns true.

Therefore, subclasses of SlackRubyBot::Commands::Base can override the permitted? private method to provide its own authorization logic. This method is intended to be exploited by user code or external gems that want to provide custom authorization logic for command execution.

class AuthorizedBot < SlackRubyBot::Commands::Base
  command 'phone home' do |client, data, match|
    client.say(channel: data.channel, text: 'Elliot!')
  end

  # Only allow user 'Uxyzabc' to run this command
  def self.permitted?(client, data, match)
    data && data.user && data.user == 'Uxyzabc'
  end
end

Animated GIFs

The SlackRubyBot::Client implementation comes with GIF support. To enable it add gem GiphyClient (official Giphy SDK) or gem giphy (older SDK, deprecated) to your Gemfile and set a Giphy key via ENV['GIPHY_API_KEY']. Obtain one from developers.giphy.com.

Note: Bots send animated GIFs in default commands and errors.

class Phone < SlackRubyBot::Commands::Base
  command 'call'

  def self.call(client, data, match)
    client.say(channel: data.channel, text: 'called', gif: 'phone')
    # Sends the text 'called' and a random GIF that matches the keyword 'phone'.
  end
end

Giphy API key is set automatically via ENV['GIPHY_API_KEY']. You can override this manually.

Giphy.configure do |config|
  config.api_key = 'key'
end

With GiphyClient you can configure the default GIF rating, which supports Y, G, PG, PG-13, and R. The default value is G.

Giphy.configure do |config|
  config.rating = 'Y' # illustrated content only, i.e. cartoons
end

If you use giphy for something else but don't want your bots to send GIFs you can set ENV['SLACK_RUBY_BOT_SEND_GIFS'] or SlackRubyBot::Config.send_gifs to false. The latter takes precedence.

SlackRubyBot.configure do |config|
  config.send_gifs = false
end

Built-In Commands

Slack-ruby-bot comes with several built-in commands. You can re-define built-in commands, normally, as described above.

[bot name]

This is also known as the default command. Shows bot version and links.

[bot name] hi

Politely says 'hi' back.

[bot name] help

Get help.

Hooks

Hooks are event handlers and respond to Slack RTM API events, such as hello or message. You can implement your own in a couple of ways:

Implementing and registering a Hook Handler

A Hook Handler is any object that respond to a call message, like a proc, instance of an object, class with a call class method, etc.

Hooks can be registered using different methods based on user preference / use case. Currently someone can use one of the following methods:

  • Pass hooks in SlackRubyBot::Server initialization.
  • Register hooks on SlackRubyBot::Server using on class method.
  • Register hooks on SlackRubyBot::Server using on instance method.

Hooks registration on SlackRubyBot::Server initialization

SlackRubyBot::Server.new(hook_handlers: {
  hello: MyBot::Hooks::UserChange.new,
  user_change: [->(client, data) {  }, ->(client, data) {}]
})

Hooks registration on a SlackRubyBot::Server instance

# Register an object that implements `call` method
class MyBot::Hooks::Hello
  def call(client, data)
    puts "Hello"
  end
end

server.on(:hello, MyBot::Hooks::Hello.new)

# or register a lambda function to handle the event
server.on(:hello, ->(client, data) { puts "Hello!" })

For example, the following hook handles user_change, an event sent when a team member updates their profile or data. This can be useful to update the local user cache when a user is renamed.

module MyBot
  module Hooks
    class UserChange
      def call(client, data)
        # data['user']['id'] contains the user ID
        # data['user']['name'] contains the new user name
        # ...
      end
    end
  end
end

Hooks registration on SlackRubyBot::Server class

Example:

module MyBot
  class MyServer < SlackRubyBot::Server
    on 'hello' do |client, data|
      # data['user']['id'] contains the user ID
      # data['user']['name'] contains the new user name
    end

    on 'user_change', ->(client, data) {
      # data['user']['id'] contains the user ID
      # data['user']['name'] contains the new user name
    }
  end
end

These will get pushed into the hook set on initialization.

Either by configuration, explicit assignment or hook blocks, multiple handlers can exist for the same event type.

Deprecated hook registration

Registering a hook method using hooks.add is considered deprecated and will be removed on future versions.

# [DEPRECATED]
server.hooks.add(:hello, MyBot::Hooks::UserChange.new)
server.hooks.add(:hello, ->(client, data) { puts "Hello!" })

Message Loop Protection

By default bots do not respond to their own messages. If you wish to change that behavior, set allow_message_loops to true.

SlackRubyBot.configure do |config|
  config.allow_message_loops = true
end

Logging

By default bots set a logger to $stdout with DEBUG level. The logger is used in both the RealTime and Web clients.

Silence logger as follows.

SlackRubyBot::Client.logger.level = Logger::WARN

If you wish to customize logger, set logger to your logger.

SlackRubyBot.configure do |config|
  config.logger = Logger.new("slack-ruby-bot.log", "daily")
end

Advanced Integration

You may want to integrate a bot or multiple bots into other systems, in which case a globally configured bot may not work for you. You may create instances of SlackRubyBot::Server which accepts token, aliases and send_gifs.

EM.run do
  bot1 = SlackRubyBot::Server.new(token: token1, aliases: ['bot1'])
  bot1.start_async

  bot2 = SlackRubyBot::Server.new(token: token2, send_gifs: false, aliases: ['bot2'])
  bot2.start_async
end

For an example of advanced integration that supports multiple teams, see slack-gamebot and playplay.io that is built on top of it.

Proxy Configuration

There are several proxy options that can be configured on Slack::Web::Client. You can also control what proxy options are used by modifying the http_proxy environment variable per Net::HTTP's documentation.

Note that Docker on OSX seems to incorrectly set the proxy, causing Faraday::ConnectionFailed, ERROR -- : Failed to open TCP connection to : (getaddrinfo: Name or service not known). You might need to manually unset http_proxy in that case, eg. http_proxy="" bundle exec ruby ./my_bot.rb.

Model-View-Controller Design

The command method is essentially a controller method that receives input from the outside and acts upon it. Complex behaviors could lead to a long and difficult-to-understand command block. A complex command block is a candidate for separation into classes conforming to the Model-View-Controller pattern popularized by Rails.

The library provides three helpful base classes named SlackRubyBot::MVC::Model::Base, SlackRubyBot::MVC::View::Base, and SlackRubyBot::MVC::Controller::Base.

Testing a command block is difficult. As separate classes, the Model/View/Controller's behavior can be tested via rspec or a similar tool.

Controller

The Controller is the focal point of the bot behavior. Typically the code that would go into the command block will now go into an instance method in a Controller subclass. The instance method name should match the command name exactly (case sensitive).

As an example, these two classes are functionally equivalent.

Consider the following Agent class which is the simplest default approach to take.

class Agent < SlackRubyBot::Bot
  command 'sayhello', 'alternate way to call hello' do |client, data, match|
    client.say(channel: data.channel, text: "Received command #{match[:command]} with args #{match[:expression]}")
  end
end

Using the MVC functionality, we would create a controller instead to encapsulate this function.

class MyController < SlackRubyBot::MVC::Controller::Base
  def sayhello
    client.say(channel: data.channel, text: "Received command #{match[:command]} with args #{match[:expression]}")
  end
  alternate_name :sayhello, :alternate_way_to_call_hello
end
MyController.new(MyModel.new, MyView.new)

Note in the above example that the Controller instance method sayhello does not receive any arguments. When the instance method is called, the Controller class sets up some accessor methods to provide the normal client, data, and match objects. These are the same objects passed to the command block.

However, the Controller anticipates that the model and view objects should contain business logic that will also operate on the client, data, and match objects. The controller provides access to the model and view via the model and view accessor methods. The inventory example provides a full example of a Model, View, and Controller working together.

A Controller may need helper methods for certain work. To prevent the helper method from creating a route that the bot will respond to directly, the instance method name should begin with an underscore (e.g. _my_helper_method). When building the bot routes, these methods will be skipped.

Calling alternate_name after the method definition allows for method aliases similar to the regular command structure. When commands can be triggered by multiple text strings it's useful to have that ability map to the controller methods too.

Lastly, the Controller class includes ActiveSupport::Callbacks which allows for full flexibility in creating before, after, and around hooks for all methods. Again, see the inventory example for more information.

Model

A complex bot may need to read or write data from a database or other network resource. Setting up and tearing down these connections can be costly, so the model can do it once upon instantiation.

The Model also includes ActiveSupport::Callbacks.

class MyModel < SlackRubyBot::MVC::Model::Base
  define_callbacks :sanitize
  set_callback :sanitize, :around, :sanitize_resource
  attr_accessor :_resource

  def initialize
    @db = setup_database_connection
  end

  def read(resource)
    self._resource = resource
    run_callbacks :sanitize do
      @db.select(:column1 => resource)
      # ... do some expensive work
    end
  end

  private

  def sanitize_resource
    self._resource.downcase
    result = yield
    puts "After read, result is #{result.inspect}"
  end
end

Like Controllers, the Model is automatically loaded with the latest version of the client, data, and match objects each time the controller method is called. Therefore the model will always have access to the latest objects when doing its work. It will typically only use the data and match objects.

Model methods are not matched to routes, so there is no restriction on how to name methods as there is in Controllers.

View

A typical bot just writes to a channel or uses the web client to react/unreact to a message. More complex bots will probably require more complex behaviors. These should be stored in a SlackRubyBot::MVC::View::Base subclass.

class MyView < SlackRubyBot::MVC::View::Base
  define_callbacks :logit
  set_callbacks :logit, :around, :audit_trail

  def initialize
    @mailer = setup_mailer
    @ftp = setup_ftp_handler
  end

  def email_admin(message)
    run_callbacks :logit do
      @mailer.send(:administrator, message)
    end
  end

  def react_thumbsup
    client.web_client.reactions_add(
      name: :thumbsup,
      channel: data.channel,
      timestamp: data.ts,
      as_user: true)
  end

  def react_thumbsdown
    client.web_client.reactions_remove(
      name: :thumbsup,
      channel: data.channel,
      timestamp: data.ts,
      as_user: true)
  end

  private

  def audit_trail
    Logger.audit("Sending email at [#{Time.now}]")
    yield
    Logger.audit("Email sent by [#{Time.now}]")
  end
end

Again, the View will have access to the most up to date client, data, and match objects. It will typically only use the client and data objects.

View methods are not matched to routes, so there is no restriction on how to name methods as there is in Controllers.

Testing

RSpec Shared Behaviors

Slack-ruby-bot comes with a number of shared RSpec behaviors that can be used in your RSpec tests.

Require slack-ruby-bot/rspec in your spec_helper.rb along with the following dependencies in Gemfile.

group :development, :test do
  gem 'rack-test'
  gem 'rspec'
  gem 'vcr'
  gem 'webmock'
end

Use the respond_with_slack_message matcher.

describe SlackRubyBot::Commands do
  it 'responds with any message' do
    expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message
  end
  it 'says hi' do
    expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message('hi')
  end
end

Use the respond_with_slack_messages matcher for multiple messages.

describe SlackRubyBot::Commands do
  it 'responds with more than one message' do
    expect(message: "#{SlackRubyBot.config.user} count").to respond_with_slack_messages
  end
  it 'says one and two' do
    expect(message: "#{SlackRubyBot.config.user} count").to respond_with_slack_messages(['one', 'two'])
  end
end

Message matchers support regular expressions.

describe SlackRubyBot::Commands do
  it 'says hi' do
    expect(message: "#{SlackRubyBot.config.user} hi").to respond_with_slack_message(/hi/)
  end
end

Check that the bot called client.start_typing(channel: 'channel').

describe SlackRubyBot::Commands do
 it 'starts typing on channel' do
    expect(message: "#{SlackRubyBot.config.user} hi").to start_typing(channel: 'channel')
  end
end

Testing Lower Level Messages

You can test client behavior at a lower level by fetching the message hook. The following example expects a bot command to call client.typing(channel: data.channel).

describe SlackRubyBot::Commands do
  let(:app) { Server.new }
  let(:client) { app.send(:client) }
  let(:message_hook) { SlackRubyBot::Hooks::Message.new }
  it 'receives a typing event' do
      expect(client).to receive(:typing)
      message_hook.call(
        client,
        Hashie::Mash.new(text: "#{SlackRubyBot.config.user} type something", channel: 'channel')
      )
    end
  end
end

Useful Libraries

Contributing

See CONTRIBUTING.

Upgrading

See CHANGELOG for a history of changes and UPGRADING for how to upgrade to more recent versions.

If you are not familiar with Slack bots or Slack API concepts, you might want to watch this video.

Author: dblock
Source Code: https://github.com/dblock/slack-ruby-bot 
License: MIT license

#ruby #bot #slack 

Slack-ruby-bot: The Easiest Way to Write A Slack Bot in Ruby
Royce  Reinger

Royce Reinger

1658447340

A Library That Enables You to Write A Complete Slack Bot Service

Slack Ruby Bot Server

Build a complete Slack bot service with Slack button integration, in Ruby.

What is this?

A library that contains a web server and a RESTful Grape API serving a Slack bot to multiple teams. Use in conjunction with slack-ruby-bot-server-events to build a complete Slack bot service, or slack-ruby-bot-server-rtm to build a (legacy) Classic RealTime Slack bot. Your customers can use a Slack button to install the bot.

Stable Release

You're reading the documentation for the next release of slack-ruby-bot-server. Please see the documentation for the last stable release, v1.2.1 unless you're integrating with HEAD. See UPGRADING when upgrading from an older version. See MIGRATING for help with migrating Legacy Slack Apps to Granular Scopes.

Make Your Own

This library alone will only register a new bot, but will not include any bot functionality. To make something useful, we recommend you get started from either slack-ruby-bot-server-events-app-mentions-sample (handles a single kind of event), or slack-ruby-bot-server-events-sample (handles all kinds of events) to bootstrap your project.

Usage

Storage

A database is required to store teams.

MongoDB

Use MongoDB with Mongoid as ODM. Configure the database connection in mongoid.yml. Add the mongoid gem in your Gemfile.

gem 'mongoid'
gem 'kaminari-mongoid'
gem 'mongoid-scroll'
gem 'slack-ruby-bot-server'

ActiveRecord

Use ActiveRecord with, for example, PostgreSQL via pg. Add the activerecord, pg, otr-activerecord and cursor_pagination gems to your Gemfile.

gem 'pg'
gem 'activerecord', require: 'active_record'
gem 'slack-ruby-bot-server'
gem 'otr-activerecord'
gem 'cursor_pagination'

Configure the database connection in config/postgresql.yml.

default: &default
  adapter: postgresql
  pool: 10
  timeout: 5000
  encoding: unicode

development:
  <<: *default
  database: bot_development

test:
  <<: *default
  database: bot_test

production:
  <<: *default
  database: bot

Establish a connection in your startup code.

ActiveRecord::Base.establish_connection(
  YAML.safe_load(
    ERB.new(
      File.read('config/postgresql.yml')
    ).result, [], [], true
  )[ENV['RACK_ENV']]
)

OAuth Version and Scopes

Configure your app's OAuth version and scopes as needed by your application.

SlackRubyBotServer.configure do |config|
  config.oauth_version = :v2
  config.oauth_scope = ['channels:read', 'chat:write']
end

The "Add to Slack" button uses the standard OAuth code grant flow as described in the Slack docs. Once clicked, the user is taken through the authorization process at Slack's site. Upon successful completion, a callback containing a temporary code is sent to the redirect URL you specified. The endpoint at that URL contains code that persists the bot token each time a Slack client is instantiated for the specific team.

Slack App

Create a new Slack App here.

Follow Slack's instructions, note the app client ID and secret, give the bot a default name, etc.

Within your application, edit your .env file and add SLACK_CLIENT_ID=... and SLACK_CLIENT_SECRET=... in it.

Run bundle install and foreman start to boot the app.

$ foreman start
07:44:47 web.1  | started with pid 59258
07:44:50 web.1  | * Listening on tcp://0.0.0.0:5000

Set the redirect URL in "OAuth & Permissions" be the location of your app. Since you cannot receive notifications on localhost from Slack use a public tunneling service such as ngrok to expose local port 9292 for testing.

$ ngrok http 5000
Forwarding https://ddfd97f80615.ngrok.io -> http://localhost:5000

Navigate to either localhost:9292 or the ngrok URL above. You should see an "Add to Slack" button. Use it to install the app into your own Slack team.

API

This library implements an app, SlackRubyBotServer::App and a service manager, SlackRubyBotServer::Service. It also provides default HTML templates and JS scripts for Slack integration.

App

The app instance checks for a working database connection, ensures indexes, performs migrations, sets up bot aliases and log levels. You can introduce custom behavior into the app lifecycle by subclassing SlackRubyBotServer::App and creating an instance of the child class in config.ru.

class MyApp < SlackRubyBotServer::App
  def prepare!
    super
    deactivate_sleepy_teams!
  end

  private

  def deactivate_sleepy_teams!
    Team.active.each do |team|
      next unless team.sleepy?
      team.deactivate!
    end
  end
end
MyApp.instance.prepare!

Service Manager

Lifecycle Callbacks

You can introduce custom behavior into the service lifecycle via callbacks. This can be useful when new team has been registered via the API or a team has been deactivated from Slack.

instance = SlackRubyBotServer::Service.instance

instance.on :started, :stopped do |team|
  # team has been started or stopped
end

instance.on :created do |team, error, options|
  # a new team has been registered
end

instance.on :deactivated do |team, error, options|
  # an existing team has been deactivated in Slack
end

instance.on :error do |team, error, options|
  # an error has occurred
end

The following callbacks are supported. All callbacks receive a team, except error, which receives a StandardError object.

callbackdescription
erroran error has occurred
creatinga new team is being registered
createda new team has been registered
bootingthe service is starting and is connecting a team to Slack
bootedthe service is starting and has connected a team to Slack
stoppingthe service is about to disconnect a team from Slack
stoppedthe service has disconnected a team from Slack
startingthe service is (re)connecting a team to Slack
startedthe service has (re)connected a team to Slack
deactivatinga team is being deactivated
deactivateda team has been deactivated

The Add to Slack button also allows for an optional state parameter that will be returned on completion of the request. The creating and created callbacks include an options hash where this value can be accessed (to check for forgery attacks for instance).

auth = OpenSSL::HMAC.hexdigest("SHA256", "key", "data")
<a href="<%= SlackRubyBotServer::Config.oauth_authorize_url %>?scope=<%= SlackRubyBotServer::Config.oauth_scope_s %>&client_id=<%= ENV['SLACK_CLIENT_ID'] %>&state=#{auth)"> ... </a>
instance = SlackRubyBotServer::Service.instance
instance.on :creating do |team, error, options|
  raise "Unauthorized response" unless options[:state] == auth
end

Service Timers

You can introduce custom behavior into the service lifecycle on a timer. For example, check whether a team's trial has expired, or periodically cleanup data.

Note that unlike callbacks, timers are global for the entire service.

instance = SlackRubyBotServer::Service.instance

instance.every :hour do
  Team.each do |team|
    begin
      # do something with every team once an hour
    rescue StandardError
    end
  end
end

instance.every :minute do
  # called every minute
end

instance.every :second do
  # called every second
end

instance.every 30 do
  # called every 30 seconds
end

Extensions

A number of extensions use service manager callbacks and service timers to implement useful functionality.

Service Class

You can override the service class to handle additional methods.

class MyService < SlackRubyBotServer::Service
  def url
    'https://www.example.com'
  end
end

SlackRubyBotServer.configure do |config|
  config.service_class = MyService
end

SlackRubyBotServer::Service.instance # MyService
SlackRubyBotServer::Service.instance.url # https://www.example.com

HTML Templates

This library provides a default HTML template and JS scripts that implement the "Add to Slack" button workflow. Customize your pages by adding a public directory in your application and starting with a index.html.erb template. The application's views and public folders are loaded by default.

You can add to or override template paths as follows.

SlackRubyBotServer.configure do |config|
  config.view_paths << File.expand_path(File.join(__dir__, 'public'))
end

Access Tokens

By default the implementation of Team stores the value of the token with all the requested OAuth scopes in both token and activated_user_access_token (for backwards compatibility), along with oauth_version and oauth_scope. If a legacy Slack bot integration bot_access_token is present, it is stored as token, and activated_user_access_token is the token that has all the requested OAuth scopes.

Sample Bots Using Slack Ruby Bot Server

Slack Bots with Granular Permissions

Legacy Slack Bots

Author: Slack-ruby
Source Code: https://github.com/slack-ruby/slack-ruby-bot-server 
License: MIT license

#ruby #slack #bot #server 

A Library That Enables You to Write A Complete Slack Bot Service
Nat  Grady

Nat Grady

1658066040

Franz: A Free Messaging App for Services Like WhatsApp, Messenger

Franz 5

Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.

Development

Preparations

Install Linux OS dependencies

Guide: Linux distribution specific dependencies

Fix native modules to match current electron node version

$ npm run rebuild

Install dependencies

Run the following command to install all dependencies, and link sibling modules with Franz.

$ npx lerna bootstrap

If you previously ran npm install it sometimes is necessary to delete your node_modules folder before running npx lerna bootstrap.

Run Franz Development App

Run these two commands simultaneously in different console tabs.

$ npm run dev
$ npm run start

Be aware that the development database will be reset regularly.

Packaging

$ npm run build

How can I support the project?

If you have found a bug that hasn't been reported yet or want to request a new feature, please open a new issue.

I need help?

Join the Franz community on Slack and get in touch with us.

Create your own plugins/recipes

You can find all the Information at the Plugins repository. For questions feel free to ask in the community Slack

Download Franz

👉 www.meetfranz.com

Or use homebrew (macOS only)

$ brew cask install franz

(Don't know homebrew? brew.sh)

Author: Meetfranz
Source Code: https://github.com/meetfranz/franz 
License: Apache-2.0 license

#electron #slack #messenger #telegram 

Franz: A Free Messaging App for Services Like WhatsApp, Messenger
Chloe  Butler

Chloe Butler

1656414000

Slack Clone using React, MaterialUI

About The Project

Slack Clone

Description

  • Slack-Clone is a clone of a slack. Implemented using React and Firebase.
  • Behind the backend, I was used React-Firebase for authentication with Google-auth, and highly secure specially for non-authorized users.
  • And I have developed a channel section to add new channels and communicate through these channels.
  • I have used firestore to keep store all the messages spread among the channels or community.
  • And ofcourse our database will be safe under google-firebase security so no worries about securities.

Features

  • The channels or messages are stored in firestore database so quickly accessible via our app.
  • I was used react-router-dom for saving server-side loads or refreshing. this functionality improve the speed for redirect to one component to another without refreshing from server-side it makes life easier, save lots of time and fast to switch without loading or refreshing the whole page.
  • Our data will be in real-time, if any changes make happens in messages or channels then it will automatically changes in our app in real-time no need to refresh our page. the app will be responsive like if you used in Desktop or Mobile devices it render same thing.

Built With

This section should list any major frameworks that you built your project using. Leave any add-ons/plugins for the acknowledgements section. Here are a few examples.

Getting Started with Create React App

This project was bootstrapped with Create React App.

Available Scripts

In the project directory, you can run:

npm start

Runs the app in the development mode.\

Open http://localhost:3000 to view it in your browser.

The page will reload when you make changes.
You may also see any lint errors in the console.

npm test

Launches the test runner in the interactive watch mode.
See the section about running tests for more information.

npm run build

Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

See the section about deployment for more information.

npm run eject

Note: this is a one-way operation. Once you eject, you can't go back!

If you aren't satisfied with the build tool and configuration choices, you can eject at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.

You don't have to ever use eject. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

Learn More

You can learn more in the Create React App documentation.

To learn React, check out the React documentation.

Code Splitting

This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting

Analyzing the Bundle Size

This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size

Making a Progressive Web App

This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app

Advanced Configuration

This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration

Deployment

This section has moved here: https://facebook.github.io/create-react-app/docs/deployment

npm run build fails to minify

This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify


Author: MuradRahmanzada
Source code: https://github.com/MuradRahmanzada/Slack-clone
License:

#react-native #react #materialui #slack #firebase 

Slack Clone using React, MaterialUI
Elian  Harber

Elian Harber

1655597940

Slackscot: Slack Bot Core/framework Written in Go

Overview

Slackscot is a slack bot core written in Go. Think of it as the assembly kit to making your own friendly slack bot. It comes with a set of plugins you might enjoy and a friendly API for you to realize your ambitious dreams (if you dreams include this sort of thing).

Requirements

Go 1.11 or above is required, mostly for go module support.

Features

Support for reactions to message updates. slackscot does the following:

Keeps track of plugin action responses and the message that triggered them

On message updates:

Update responses for each triggered action

Delete responses that aren't triggering anymore (or result in errors during the message update)

On deletion of triggering messages, responses are also deleted

Limitation: Sending a message automatically splits it into multiple slack messages when it's too long. When updating messages, this spitting doesn't happen and results in an message too long error. Effectively, the last message in the initial response might get deleted as a result. Handling of this could be better but that is the current limitation 😕

Support for threaded replies to user message with option to also broadcast on channels (disabled by default). See configuration example below where both are enabled.

  • Plugin actions may also explicitely reply in threads with/without broadcasting via AnswerOption

Concurrent processing of unrelated messages with guarantees of proper ordering of message updates/deletions

Simple extensible storage API for persistence in two flavors: StringStorer and BytesStorer. Both are basic key:value maps. A default file-based implementation is provided backed by leveldb

Implementation of StringStorer backed by Google Cloud Datastore. See datastoredb's godoc for documentation, usage and example.

In-memory implementation of StringStorer wrapping any StringStorer implementation to offer low-latency and potentially cost-saving storage implementation well-suited for small datasets. Plays well with cloud storage like the datastoredb See inmemorydb's godoc for documentation, usage and example.

Support for various configuration sources/formats via viper

Support for various ways to implement functionality:

  1. scheduled actions: run something every second, minute, hour, week. Oh Monday is a plugin that demos this by sending a Monday greeting every Monday at 10am (or the time you configure it to).
  2. commands: respond to a command directed at your slackscot. That means something like @slackscot help or a direct message help sent to slackscot.
  3. hear actions (aka "listeners"): actions that evaluated for a match on every message that slackscot hears. You'll want to make sure your Match function isn't too heavy. An example is the "famous" finger quoter plugin

Experimental and subject to change: Testing functions to help validate plugin action behavior (see example in triggerer_test.go). Testing functions are found in assertplugin and assertanswer

Built-in help plugin supporting a decently formatted help message as a command listing all plugins' actions. If you'd like some actions to not be shown in the help, you can set Hidden to true in its ActionDefinition (especially useful for hear actions)

The plugin interface as a logical grouping of one or many commands and hear actions and/or scheduled actions

Support for injected services providing plugins easy access to an optionally caching user info and a logger.

Demo

  • slackscot deleting a triggered reaction after seeing a message updated that caused the first action to not trigger anymore and a new action to now trigger (it makes sense when you see it)

different-action-triggered-on-message-update

  • slackscot updating a triggered reaction after seeing a triggering message being updated

same-action-answer-update-on-message-update

  • slackscot deleting a reaction after seeing the triggering message being deleted

reaction-deletion-on-message-delete

  • slackscot threaded replies enabled (with broadcast => on)

threaded-reply-with-broadcast

The Name

The first concrete bot implementation using this code was youppi, named after the great mascot of the Montreal Expos and, when the Expos left Montreal, the Montreal Canadiens.

Slackscot is a variation on the expected theme of slackbot with the implication that this is the core to more than just a regular bot. You know, a friendly company mascot that hangs out on your slack.

Concepts

Commands: commands are well-defined actions with a format. Slackscot handles all direct messages as implicit commands as well as @mention <command> on channels. Responses to commands are directed to the person who invoked it.

Hear actions: those are listeners that can potentially match on any message sent on channels that slackscot is a member of. This can include actions that will randomly generate a response. Note that responses are not automatically directed to the person who authored the message triggering the response (although an implementation is free to use the user id of the triggering message if desired).

Create Your Own Slackscot

Slackscot provides the pieces to make your mascot but you'll have to assemble them for him/her to come alive. The easiest to get started is to look at a real example: youppi.

youppi running

The godoc is also a good reference especially if you're looking to implement something like a new implementation of the storer interfaces.

Assembling the Parts and Bringing Your slackscot to Life

Here's an abbreviated example of how youppi does it:

package main

import (
    "github.com/alexandre-normand/slackscot"
    "github.com/alexandre-normand/slackscot/config"
    "github.com/alexandre-normand/slackscot/plugins"
    "github.com/alexandre-normand/slackscot/store"
    "github.com/spf13/viper"
    "gopkg.in/alecthomas/kingpin.v2"
    "log"
    "os"
    "io"
)

const (
    name           = "youppi"
)

func main() {
    kingpin.Version(VERSION)
    kingpin.Parse()

    // TODO: initialize storer implementations required by plugins and do any other initialization 
    // required
    ...

    // This is the where we create youppi with all of its plugins
    youppi, err := slackscot.NewBot(name, v, options...).
        WithPlugin(plugins.NewKarma(karmaStorer)).
        WithPlugin(plugins.NewTriggerer(triggererStorer)).
        WithConfigurablePluginErr(plugins.FingerQuoterPluginName, func(conf *config.PluginConfig) (p *slackscot.Plugin, err error) { return plugins.NewFingerQuoter(conf) }).
        WithConfigurablePluginCloserErr(plugins.EmojiBannerPluginName, func(conf *config.PluginConfig) (c io.Closer, p *slackscot.Plugin, err error) {
            return plugins.NewEmojiBannerMaker(conf)
        }).
        WithConfigurablePluginErr(plugins.OhMondayPluginName, func(conf *config.PluginConfig) (p *slackscot.Plugin, err error) { return plugins.NewOhMonday(conf) }).
        WithPlugin(plugins.NewVersionner(name, version)).
        Build()
    defer youppi.Close()

    if err != nil {
        log.Fatal(err)
    }

    err = youppi.Run()
    if err != nil {
        log.Fatal(err)
    }
}

Configuration Example

You'll also need to define your configuration for the core, used built-in plugins and any configuration required by your own custom plugins (not shown here). Slackscot uses viper for loading configuration which means that you are free to use a different file format (yaml, toml, env variables, etc.) as desired.

{
   "token": "your-slack-bot-token",
   "debug": false,
   "responseCacheSize": 5000,
   "userInfoCacheSize": 0,
   "maxAgeHandledMessages": 86400,
   "timeLocation": "America/Los_Angeles",
   "storagePath": "/your-path-to-bot-home",
   "replyBehavior": {
      "threadedReplies": true,
      "broadcastThreadedReplies": true
   },
   "plugins": {
      "ohMonday": {
            "channelIDs": ["slackChannelId"]
      },
      "fingerQuoter": {
         "frequency": "100",
         "channelIDs": []
      },
      "emojiBanner": {
         "figletFontUrl": "http://www.figlet.org/fonts/banner.flf"
      }
   }
}

Creating Your Own Plugins

It might be best to look at examples in this repo to guide you through it:

  • The simplest plugin with a single command is the versioner
  • One example of scheduled actions is oh monday
  • One example of a mix of hear actions / commands that also uses the store api for persistence is the karma

Contributing

  1. Fork it (preferrably, outside the GOPATH as per the new go modules guidelines)
  2. Make your changes, commit them (don't forget to go build ./... and go test ./...) and push your branch to your fork
  3. Open a PR and fill in the template (you don't have to but I'd appreciate context)
  4. Check the code climate and travis PR builds. You might have to fix things and there's no shame if you do. I probably won't merge something that doesn't pass CI build but I'm willing to help to get it to pass 🖖.

Open-telemetry integration

Slackscot now supports integration with opentelemetry. To aid with the addition of new metrics, you can find a gowrap template here. To add a metrics to a new interface, you can do something like

gowrap gen -p . -i <interfaceName> -t opentelemetry.template -o <interfaceName>metrics.go

When updating the template, you should consider running go generate in order to refresh the already generated files with the template changes.

Some Credits

slackscot uses Norberto Lopes's Slack API Integration found at https://github.com/nlopes/slack. The core functionality of the bot is previously used James Bowman's Slack RTM API integration and was heavily inspired by talbot, also written by James Bowman.

Author: Alexandre-normand
Source Code: https://github.com/alexandre-normand/slackscot 
License: MIT license

#go #golang #bot #slack 

Slackscot: Slack Bot Core/framework Written in Go
Elian  Harber

Elian Harber

1655585460

Hanu: Golang Framework for Writing Slack Bots

hanu - Go for Slack Bots!

The Go framework hanu is your best friend to create Slack bots! hanu uses allot for easy command and request parsing (e.g. whisper <word>) and runs fine as a Heroku worker. All you need is a Slack API token and you can create your first bot within seconds! Just have a look at the hanu-example bot or read my tutorial

Features

  • Respond to mentions
  • Respond to direct messages
  • Auto-Generated command list for help
  • Works fine as a worker on Heroku

Usage

Use the following example code or the hanu-example bot to get started.

package main

import (
    "log"
    "strings"

    "github.com/sbstjn/hanu"
)

func main() {
    slack, err := hanu.New("SLACK_BOT_API_TOKEN")

    if err != nil {
        log.Fatal(err)
    }

    Version := "0.0.1"

    slack.Command("shout <word>", func(conv hanu.ConversationInterface) {
        str, _ := conv.String("word")
        conv.Reply(strings.ToUpper(str))
    })

    slack.Command("whisper <word>", func(conv hanu.ConversationInterface) {
        str, _ := conv.String("word")
        conv.Reply(strings.ToLower(str))
    })

    slack.Command("version", func(conv hanu.ConversationInterface) {
        conv.Reply("Thanks for asking! I'm running `%s`", Version)
    })

    slack.Listen()
}

The example code above connects to Slack using SLACK_BOT_API_TOKEN as the bot's token and can respond to direct messages and mentions for the commands shout <word> , whisper <word> and version.

You don't have to care about help requests, hanu has it built in and will respond with a list of all defined commands on direct messages like this:

/msg @hanu help

Of course this works fine with mentioning you bot's username as well:

@hanu help

Slack

Use direct messages for communication:

/msg @hanu version

Or use the bot in a public channel:

@hanu version

Dependencies

Credits

Author: sbstjn
Source Code: https://github.com/sbstjn/hanu 
License: MIT license

#go #golang #chat #slack 

Hanu: Golang Framework for Writing Slack Bots