blackjid
5/5/2014 - 4:51 PM

Google Calendar Attendees widget for Dashing

Google Calendar Attendees widget for Dashing

// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color:  #EEC647;
$value-color:       #fff;

$title-color:       rgba(255, 255, 255, 0.7);
$label-color:       rgba(255, 255, 255, 0.7);
$moreinfo-color:    rgba(255, 255, 255, 0.7);

// ----------------------------------------------------------------------------
// Widget-list styles
// ----------------------------------------------------------------------------
.widget-attendees {

  background-color: $background-color;
  vertical-align: top;
  padding: 15px 12px 40px 12px !important;

  .title {
    color: $title-color;
    display: inline-block;

    .counter{
      display: inline-block;
      width: 40px;
      height: 40px;
      line-height: 40px;
      background: #F14D00;
      border-radius: 20px;
      font-size: 30px;
      font-weight: bold;
    }
  }

  .value {
    font-weight: 600;
    color: $value-color;
  }

  ol {
    list-style-position: inside;
  }

  .list-nostyle {
    list-style: none;
  }

  .label {
    color: $label-color;
  }

  .updated-at {
    color: rgba(0, 0, 0, 0.3);
  }

  .more-info {
    color: $moreinfo-color;
  }

  .attendee {
    float: left;
    margin: 4px;
    position: relative;

    .counter{
      position: absolute;
      width: 22px;
      height: 22px;
      z-index: 10;
      top: -4px;
      right: -4px;
      line-height: 22px;
      background: #F14D00;
      border-radius: 11px;
      font-size: 12px;
      font-weight: bold;
    }
  }
}
# encoding: UTF-8

require 'google/api_client'
require 'date'
require 'time'
require 'digest/md5'
require 'active_support'
require 'active_support/all'

# Update these to match your own apps credentials
service_account_email = ENV['GOOGLE_SERVICE_ACCOUNT_EMAIL'] # Email of service account
key_file = ENV['GOOGLE_SERVICE_PK_FILE'] # File containing your private key
key_secret = ENV['GOOGLE_SERVICE_KEY_SECRET'] # Password to unlock private key
calendarID = ENV['ATTENDEE_CALENDAR_ID'] # Calendar ID.
eventId = ENV['ATTENDEE_EVENT_ID'] # Event ID
defaultImg = ENV['DEFAULT_GRAVATAR'] # Url to image to show as default when no gravatar
next_event_time = ENV['NEXT_EVENT_TIME'] || '14:00' # Time to start showing the next event
next_event_timezone = ENV['NEXT_EVENT_TIMEZONE'] # Time zone to parse the next event time in

# Get the Google API client
client = Google::APIClient.new(:application_name => 'Google Calendar Attendee Widget',
  :application_version => '0.0.1')

# Load your credentials for the service account
if not key_file.nil? and File.exists? key_file
  key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
else
  key = OpenSSL::PKey::RSA.new ENV['GOOGLE_SERVICE_PK'], key_secret
end

client.authorization = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => 'https://www.googleapis.com/auth/calendar.readonly',
  :issuer => service_account_email,
  :signing_key => key)

# Start the scheduler
SCHEDULER.every '60s', :first_in => 4 do |job|

  # Request a token for our service account
  client.authorization.fetch_access_token!

  # Get the calendar API
  calendar = client.discovered_api('calendar','v3')

  # Start and end dates
  Time.zone = next_event_timezone
  today = Date.today.in_time_zone
  tomorrow = Date.today.next_day.in_time_zone
  after_tomorrow = Date.today.next_day(2).in_time_zone

  # Check if the current time has passed the defined threshold
  show_tomorrow_event = Time.zone.now >= Time.zone.parse(next_event_time)

  # Search event dates
  startDate = !show_tomorrow_event ? today.to_datetime.rfc3339 : tomorrow.to_datetime.rfc3339
  endDate = !show_tomorrow_event ? tomorrow.to_datetime.rfc3339 : after_tomorrow.to_datetime.rfc3339

  # Get the events
  events = client.execute(:api_method => calendar.events.instances,
                          :parameters => {
                                :calendarId => calendarID,
                                :eventId => eventId,
                                :maxResults => 1,
                                :timeMin => startDate,
                                :timeMax => endDate
                              }
                          )

  # Set the event if there is one found
  if events.data.items.count > 0
    # Get the first matching event
    calendar_event = events.data.items.first

    # Get only the attedees that had accepted
    accepted_attendees = calendar_event.attendees.select {|attendee| attendee.responseStatus == 'accepted'}

    # Prepare the attendees object
    accepted_attendees = accepted_attendees.map do |attendee|
      email = attendee.email.downcase

      # Force additional guests property
      attendee['additionalGuests'] = attendee['additionalGuests'] || 0

      # Set the gravatar url
      hash = Digest::MD5.hexdigest(email)
      attendee[:gravatar] = "http://www.gravatar.com/avatar/#{hash}"
      attendee[:gravatar] += "?default=#{defaultImg}" if defaultImg
      attendee
    end

    # Event hash to pass to dashing
    event = {
      title: calendar_event.summary,
      attendees: accepted_attendees,
      total_attendees: accepted_attendees.reduce(accepted_attendees.length){|r, v| r + v['additionalGuests']},
    }
  end

  # Update the dashboard
  send_event('attendees', {
    calendar_event: event,
    tomorrow_event: show_tomorrow_event
  })
end
<div data-renderif="calendar_event">
    <h1 class="title">
        <span data-bind="calendar_event.title"></span>
        <span class="counter" data-bind="calendar_event.total_attendees"></span>
    </h1>
    <ul class="clearfix">
      <li class="attendee" data-foreach-item="calendar_event.attendees">
        <img class="gravatar" data-bind-src="item.gravatar" width="62px" height="62px"/>
        <div class="counter" data-bind="'+%{extras}' | interpolate {'extras': 'item.additionalGuests'}" data-insertif="item.additionalGuests"></div>
      </li>
    </ul>

    <p class="more-info">
        <span data-bind="detailMessage"></span>
    </p>
    <p class="updated-at" data-bind="updatedAtMessage"></p>
</div>
<div data-hideif="event">
    <h1 class="title" data-bind="noEventMessage"></h1>
</div>
class Dashing.Attendees extends Dashing.Widget

  ready: ->
    # This is fired when the widget is done being rendered

  onData: (data) ->
    @set('detailMessage', if data.tomorrow_event then @get('tomorrowMessage') else @get('todayMessage') )

Description

A Dashing widget for displaying the number of attendees for a specific calendar event on Google Calendar

It's specially designed to be used against a recursive event. For example, we use it at platanus to show how many people and who is going to have lunch in the office.

Made by platanus in Chile

Dependencies

google-api-ruby-client rails/activesupport

Add it to dashing's gemfile:

gem 'google-api-client'
gem 'activesupport'

and run bundle install.

Usage

To use this widget, you'll first need to set up a Google API project.

  1. Create and download a new private key for Google API access.

    1. Go to https://code.google.com/apis/console
    2. Click 'Create Project'
    3. Enable 'Analytics API' service and accept both TOS's
    4. Click 'API Access' in the left-hand nav menu
    5. Click 'Create an OAuth 2.0 Client ID'
    6. Enter a product name (e.g. Dashing Widget) - logo and url are optional
    7. Click 'Next'
    8. Under Application Type, select 'Service Account'
    9. Click 'Create Client ID'
    10. Click 'Download private key' NOTE: This will be your only opportunity to download this key.
    11. Note the password for your new private key ('notasecret')
    12. Close the download key dialog
    13. Find the details for the service account you just created and copy it's email address which will look something like this: 210987654321-3rmagherd99kitt3h5@developer.gserviceaccount.com - you'll need it in environmental variables later
  2. Setup your widget

    1. You can install the widget with dashing install 2f0b6010d6ffab479d61, or manually add each file in the corresponding location

    2. Setup your environmental variables

      GOOGLE_SERVICE_ACCOUNT_EMAIL # Email of service account
      GOOGLE_SERVICE_PK_FILE # File containing your private key
      GOOGLE_SERVICE_KEY_SECRET # Password to unlock private key 'notasecret'
      ATTENDEE_CALENDAR_ID # Calendar ID.
      ATTENDEE_EVENT_ID # Event ID
      DEFAULT_GRAVATAR # Url to image to show as default when no gravatar
      NEXT_EVENT_TIME # Time to start showing the next event 'America/Los Angeles'
      
1. Add the widget HTML to your dashboard

    ```html
    <li data-row="1" data-col="4" data-sizex="1" data-sizey="1">
      <div data-id="attendees"
           data-view="Attendees"
           data-today-message="Today lunch"
           data-tomorrow-message="Tomorrow lunch"
           data-no-event-message="No lunch"
           data-updatedAtMessage="Updated"></div>
         <i class="fa fa-cutlery icon-background"></i>
    </li>
    ```

Notes

To set your PK12 certificate in heroku you can follow this guide http://ar.zu.my/how-to-store-private-key-files-in-heroku/