GSoC product submission

As GSoC final evaluations have been started, this post will summarize the project experience and the tasks I worked on. I will also provide the links to the code and the challenges I faced.

You can see all the commits merged during GSoC here

Features Implemented in TSP during GSoC

Migrating to Bootstrap 3

TSP was built on Bootstrap 2 but as there has been a significant amount of changes in the latest version of Bootstrap it was necessary to migrate to the latest framework, so writing a new theme does not imply using an outdated CSS framework. This was my first task in which I updated TSP to Bootstrap 3.

Index
TSP on Bootstrap 3

You can visit my previous post for more information here.

To check the Pull Request for this task click here.

Challenges: In TSP user can choose between two themes the default bootstrap theme and bento theme. So I had to make the changes while keeping both the themes in mind and also had to update the bento theme to work on Bootstrap 3, but I think it was worth as Bento theme looks pretty nice you check it out here.

Rubocop

There was no Style Guide defined for TSP. And as a style guide is very important for an open source project. We added Rubocop, a static code analyzer which enforce many of the guidelines outlined in the Ruby Style Guide.

Pull Request: #55

Event Email

With this feature tsp members and event organizers can easily notify the event participants based on their travel requests state. You can choose the participants easily based on the states like submitted, incomplete, approved,etc and don’t need to select each user one by one. Also you can use the markdown syntax in the email body.

Index
Event Email view

Blog Post having details for this feature: Event Email.

Pull requests related to this feature: #54, #56, #65, #81 and #88

Preview emails

To test and preview your emails you can use letter opener web which has been added in TSP. Letter opener web can be used on heroku also.

Check out the Pull Request here #73.

Participants view

Now the TSP members and the event organizers can view the list of participants for an event with their details and request status. This makes it easy for event organizers to keep track of the participants.

Index
Participants View

Pull requests: #80 and #92.

Challenges: To complete this task we needed to fetch the users details participating in the event but fetching them directly could have void the user’s privacy. So to maintain their privacy we needed to fetch records based on the logged in user’s ability but users doesn’t had the ability to view some user’s details. So to accomplish this we fetched the requests accessible by the person and then the user details with the help of the request.

Implementation of Event Organizer concept

Now in TSP you can create event organizers for an event. An event organizer can view the participants list and notify them with the help of the event email feature. An event organizer can be easily added or removed by a tsp member.

Index
Event Organizer Index Page

Blog Post having more details for this feature Event Organizer.

Pull Request related to this feature: #83, #91, #97 and #98.

Challenges: We wanted to have the event organizer as a local role to an event. So we had to create a many to many association between the user & the event and use nested resources in the ability file to accomplish this. It was a little tricky but it was fun playing with cancancan. For more details regarding the implementation you can check out the above mentioned blog post.

Heroku deployment

We have created a demo version of travel support program on heroku. There you can try out the above mentioned features and many more. Have a look at them here: http://travel-support.herokuapp.com/ .

Project Experience

The experience of working in openSUSE during Google Summer of Code was full of learning and joy. I learned about better code practices, Test Driven Development and a lot about Ruby on Rails.

I would like to thank my mentors Björn Geuken and Christian Buckmayer and the openSUSE community for this awesome summer.

I will continue working on Open Source projects and of course on TSP. I would also recommend other people to work on open source projects as they help you a lot in developing your skills and also you get to meet some really amazing people. If you want to work on Open Source projects you can have a look at some great projects provided by openSUSE.

GSoC Second evaluation

Implementing the concept of event organizer in TSP

During the second phase of GSoC, one of my tasks was to implement the event organizer feature. Now with the help of this tsp members can easily assign event organizers for an event. An event consists of various organizers to manage certain attributes for that event such as checking if the attendees have signed up or not, checking the state of their requests, reminding them about important dates and timings. Before this feature, event organizers always had to bug someone for these details.

Github link for this issue -> event organizer feature.

This feature was requested by KDE e.V. Travel Cost Reimbursement initiative .

Creating the event organizer role

TSP has various roles defined such as tsp, supervisor, administrative, requester, etc which are all global roles. But event organizer is not a global role. An event organizer has the ability to see the participants of an event and manage event email.

So to define this role we created a many to many association between a user and an event.

create_table "event_organizers", force: true do |t|
  t.integer "event_id"
  t.integer "user_id"
end

And now a user can be defined as a event organizer for various events.

# Event organizer for events
has_many :event_organizers
# Events for which the user is an event organizer
has_many :events, through: :event_organizers

Defining the abilities of an event organizer

Starting by writing some tests for the event organizer`s abilities. In the tests below there are two users wedge and luke in which luke is an event organizer. So signing in with wedge we are not allowed to access the event email feature on the other hand we can access the event email for the party event for which luke is defined as an event organizer but he cannot do the same for the hoth hackathon event.

scenario 'When logged in as a requester' do
  sign_in_as_user(users(:wedge))

  visit event_event_emails_path(events(:party))
  page.should have_content 'You are not allowed to access this page'

  visit event_event_emails_path(events(:hoth_hackaton))
  page.should have_content 'You are not allowed to access this page'
end
 
scenario 'When logged in as an event organizer' do
  sign_in_as_user(users(:luke))

  visit event_event_emails_path(events(:party))
  page.should have_content "Event email Emails for Death Star's destruction celebration"

  visit event_event_emails_path(events(:hoth_hackaton))
  page.should have_content 'You are not allowed to access this page'
end

Now defining the abilities for an event organizer, TSP uses cancancan for authorization. Cancancan uses an Ability class to define user permissions. TSP uses ActiveHash for user roles. So you can easily define the abilities for a particular role very easily, like done in the Ability file of TSP. But we have not created the event organizer as a global role, so how to defined the abilities for this role. Here comes the interesting part, cancancan supports Nested Resources so with the help of this we can define the abilities in the following way:

user.events.each do |e|
  can :manage, EventEmail, event: { id: e.id }
end

What does the above code do? It provides the ability to manage the Event Email to a user who is an event organizer of that event.

Adding/Removing an event organizer for an event

Tsp members can easily add event organizers by searching the users with the help of their email address.

Index
Searching with the help of auto complete and adding an event organizer

For the auto complete function we are using `rails4-autocomplete’ gem. This gem uses the jQuery-ui Autocomplete and is very easy to use. You just have to define some custom css to make the dropdown look better ;), if you want you can have a look here for the css we are using in TSP.

Event organizers for an event are listed on /events/:event_id/organizers

Index
Index view of event organizers

A remove button is provided in every row so that the tsp members can also easily remove the event organizer for an event.

Event Organizers controller:

class EventOrganizersController < InheritedResources::Base
  autocomplete :user, :email
  belongs_to :event
  actions :all, except: [:show, :edit, :update]

  def create
    @event_organizer.user = User.find_by(email: params[:event_organizer][:user_email])
    create!(notice: 'Event Organizer Added')
  end

  def permitted_params
    params.permit(event_organizer: [:user_email])
  end
end

The autocomplete method is from the rails4_autocomplete gem to generate user email’s. And as we are using Inherited resources we have defined the nesting with the help of belongs_to. In the create action we are searching a user with the help of his email and then the user is added as an event organizer.

The new action view to add the event organizers:

%h3 Add an event organizer for #{@event.name}
.col-md-3
  = simple_form_for(resource, url: event_event_organizers_path) do |f|
    = f.error :user_id
    = f.input :user_email, url: autocomplete_user_email_event_event_organizers_path, as: :autocomplete, label: false, :input_html => {class: 'form-control', placeholder: 'Search by email'}
    .form-group  
      = f.submit "Add", class: 'btn btn-primary btn-sm'

For the autocomplete, as we are using simple form we can easily do it with the help of as: :autocomplete, also there is an error field for custom error messages.

Other tasks during the second evaluation

Implementing the markdown preview feature in the event emails

We are using the Redcarpet gem for markdown in TSP which was implemented during the event email feature you can read about it in my previous post, if you have already read it then its awesome :)

How the feature looks:

Markdown
Filling in the body field

We have used bootstrap tabs here for the Body and Preview tabs.

Preview
Markdown Preview

As Redcarpet is a ruby library we can’t use it on the client side. The first thing which comes to mind is Ajax isn’t it? Then lets just use ajax here. This is how the ajax request looks

$('a[href=#preview]').click ->
  $("#preview_screen").html("<h3>Loading...</h3>")
  $.ajax
   url: '/events/' + $(this).data('event-id') + '/event_emails/preview'
   type: 'POST'
   data: content: $('#event_email_body').val()

The above requests is written in coffee script, as you can see we are using a post type request and passing the body field value as the data. Then we collect the data in an instance variable in the preview action defined in the event_emails controller and then we can just use the markdown method which we created with the help of redcarpet to process the data. Remember to create a route for the following request in the routes.rb file.

// In preview.js.erb
$('#preview_screen').html('<%= j markdown(@content) %>');

The above code will fill our preview section with the converted html. That’s it, simple wasn’t it :)

Testing the above code, we can do it by just checking if the preview section contains the converted html or not.

scenario 'Viewing the markdown preview', js: true do
  sign_in_as_user(users(:tspmember))
  visit new_event_event_email_path(events(:party))

  fill_in 'event_email_body', with: "# Death Star's destruction celebration"
  click_link 'Preview'
  within(:xpath, '//*[@id="preview_screen"]') do
    page.should have_css('h1', text: "Death Star's destruction celebration")
  end
end

For the implementation of these features you can have a look at the following PR’s:

And of course I would have not been able to implement these features without the help of my amazing mentors Björn Geuken and Christian Buckmayer :)

To know more about Travel Support Program visit TSP

Second task of GSoC

Sending Email to Event participants

My second task in GSoC was to implement a feature to send emails to event participants. This feature included selecting the email recipients on the basis of state of their requests (request submitted by a user) i.e. submitted, approved, accepted, etc.

This feature is important because it provides TSP members a facility to easily notify the users participating in an event. Also the option of selecting users on the basis of their request state saves a lot of time of the members. This feature covers many requirements of the TSP members such as, sending deadline emails, information about changed date and timings, informing the participants about exciting rounds in an event,etc.

This feature was requested by KDE e.V. Travel Cost Reimbursement initiative .

How the Feature looks and its implementation

This feature provides three views: index, new and show. Lets see how the actions for these views are defined in the controller.

class EventEmailsController < InheritedResources::Base
  actions :all, except: [:edit, :update, :destroy]
  belongs_to :event

  def create
    @event_email.user = current_user
    create!(notice: 'Email Delivered')
    return unless @event_email.errors.empty?
    @event_email[:to].split(',').each do |e|
      user = User.find_by(email: e)
      EventMailer.notify_to(user, :event_info, @event_email)
    end
  end

  protected

  def permitted_params
    params.permit(event_email: [:to, :subject, :body])
  end
end

Great, you noticed that we have not defined the index, new and show action in the controller as we are inheriting from InheritedResources::Base which inherits all the restful actions for us. So why we have defined the create action? Because we want to call the Event mailer in it to send the mails. But lets just come back to this mailer part in a minute.

Lets have a look at the Email new view

This is the Email New view

As we can see a dropdown is provided to select the recipients for the To field with the states as its options as requested in the feature.

So how to implement this?

Creating a method in the Events helper to return email ids of the users.

def users_for_event(state)
  req = @event.requests
  req = req.where(state: state) if state != 'all'
  user_email = req.map { |e| e.user.email }.uniq
end

But can this method insert the values in the To field ? No Of course not, so lets write some javascript coffeescript for this.

states = (state) ->
  $('#state'+state).click ->
    users = $('#state'+state).data('users')
    $('#event_email_to').val(users)
    if users.length == 0
      $('#event_email_to').attr('placeholder', 'No recipients present for ' + state + ' state')

states state for state in ['All', 'Accepted', 'Incomplete', 'Submitted', 'Approved', 'Cancel']

You noticed that we are using data-attributes for the values here, you must be using sharingan ;) So why we have not written inline javascript here which might have been easy? Because the rails guide suggests to use Unobtrusive JavaScript, and we cannot go against the rails guide, can we ?

So what does the above code do: we have defined a function which adds a click event listener to the links of the dropdown and when a user clicks the link the data is fetched from the data-users attribute and filled in the To field and if their are no recipients present it adds a placeholder to indicate that.

Enough talk about the To field lets have a look at the body field, sending unformatted text in a mail might not look good so we have added a markdown functionality to the body field, cool right :) . You can easily do this with the help of the Redcarpet gem.

Before going to the mailer portion lets have a quick look at the other two views show and index.

This is the Email Show view

Show view provides all the details of an email sent.

This is the Email index view

Index view provides a list of all the emails sent with some attributes like name of the sender and email sent time.

Time to throw some light on the mailer

Creating a mailer in rails is very easy as it is pretty much like creating a controller. Lets have a look at the Event mailer used in this feature

class EventMailer < ApplicationMailer
  def event_info(to, email)
    @email = email
    mail(from: @email.user.email,
         to: to,
         subject: @email[:subject])
  end
end

We can use this event_info action to send our mails. But did you notice that above in the controller create action we are not calling this method instead calling some other method notify_to. Which method is this and why are we using this? We have defined this method in the ApplicationMailer for some extra features which you can have a look at here. But the important part of using it here is to use delayed jobs. As it will save us the time of waiting for the external mail service to send the mail.

We can’t finish a feature without tests, so lets write some tests for it.

Tests for the feature

To test the delivery of the mails we can track ActionMailer::Base.deliveries.size and check its value after we are finish sending the mails. Have a look at the test file for this feature. We are testing with the help of rspec. Using capybara, capybara-webkit etc.

Tests for the Event Mailer

require 'spec_helper'

describe Event, type: :mailer do
  fixtures :all
  describe 'Event Info' do
    let(:mail) { EventMailer.event_info(event_emails(:party_info).to, event_emails(:party_info)).deliver }

    it 'renders the headers' do
      expect(mail.subject).to eq('Testing mail')
      expect(mail.to).to eq(['test@example.com'])
    end

    it 'renders the body' do
      expect(mail.body.encoded).to match('This is a test mail')
    end
  end
end

In the above feature tests we checked for if we are able to create our mails and that they are getting delivered. In the mailer specs we check that if our mail is send to the correct person and that it has the correct subject and body. In the above test we are testing event_info method of the Event Mailer using fixtures. We can check the value of fields easily with the help of expect().to and eq. It is similar to writing the model specs.

Testing using Letter Opener

A fast and efficient option to test your email. Letter Opener helps you in previewing the email in the browser instead of sending it. Which means you don’t need to set up email delivery in your development environment.

Steps for using letter opener

  • Add the letter_opener gem in the Gemfile
    gem "letter_opener", :group => :development
    
  • Then set the delivery method in config/environments/development.rb
      config.action_mailer.delivery_method = :letter_opener
    

For the implementation of this feature you can have a look at the following PR’s:

Thanks to Björn Geuken and Christian Buckmayer for helping me in this task.

To know about Travel Support Program visit TSP

Migrate to the latest version of Bootstrap

Migrating to Bootstrap v3

My first task in GSoC was to update TSP to the latest version of Bootstrap. TSP was built on Bootstrap 2 using the twitter-bootstrap-rails gem with LESS. Though the latest version of Bootstrap is v4, but currently it is in Beta phase, so we will be updating to Bootstrap v3.

Bootstrap

Bootstrap makes front-end web development faster and easier. It’s made for folks of all skill levels, devices of all shapes, and projects of all sizes. There has been a lot changes made in the Bootstrap v3, many new classes have been introduced and some of the classes of Bootstrap v2 have been modified or removed. What’s new in v3.0

Twitter Bootstrap Rails gem

One of the ways to use Bootstrap in Rails is using twitter-bootstrap-rails gem. With the help of this gem you can use the Bootstap stylesheets in two ways by using the plain CSS or with LESS. It is very easy to integrate this gem in you rails project. To use it with LESS you have to include the following gems

gem "therubyracer"
gem "less-rails"
gem "twitter-bootstrap-rails"

Less is a CSS pre-processor, meaning that it extends the CSS language, adding features that allow variables, mixins, functions and many other techniques that allow you to make CSS that is more maintainable, themeable and extendable. For more information visit lesscss.org

To use it with plain CSS you just have to include the twitter-bootstrap-rails gem. For more details on How to use this gem click here.

Steps to Update to Bootstrap 3 from Bootstrap 2

When using bootstrap with the help of twitter-bootstrap gem

  • Update the twitter-boostrap-rails gem to the latest version (here it is 3.2.2) with bundle udpate twitter-boostrap-rails this will also update the dependencies for the gem.

  • If you are using LESS do rails generate bootstrap:install less to generate the boostrap includes

    The latest version of boostrap only generates the bootstrap_and_overrides.css.less file for the stylesheets directory, you can define any overrides for the classes in this file.

Updating the Bootstrap classes

  • To view the major style changes click here

  • Also there are various classes that have been removed in v3. For those classes you can use their equivalents or create your own with the classes in v3.

For any issues refer to the Bootstrap documentation. Also if you are using simple form in your application you have to generate the updated intializers of simple_form.

Special thanks to Björn Geuken for helping me in this task.

To know about Travel Support Program visit TSP or you can read my previous post.

GSoC 2017

About the Organization

suse

openSUSE, formerly SUSE Linux and SuSE Linux Professional, is a Linux-based project and distribution sponsored by SUSE Linux GmbH and other companies. It is widely used throughout the world. The focus of its development is creating usable open-source tools for software developers and system administrators, while providing a user-friendly desktop, and feature-rich server environment.

Project

Make the Travel Support Application useful for more organizations

TSP is a Ruby on Rails based application to manage the requests and reimbursements from travel help programs of free software organizations. Originally developed for the openSUSE Travel Support Program it was adopted recently by the KDE e.V. Travel Cost Reimbursement initiative.

The project goal is about making the tool more useful for KDE e.V. and possible future adopters. Implementing new features such as creating a new role of event organizer to manage the events, a feature to send mails to the event participants, migrate to the latest front-end framework, moving the DSL logic from the models to the configuration files so that adapting the application becomes easier.

For this project my mentor is Christian Buckmayer (member of the SUSE Build Solutions team). Other than being highly skilled Chris is a very friendly and helpful person. He is involved in the development of a lot of awesome applications such as an Open Build Service, SUSE Studio and OSEM. I hope to learn a lot from him in the given period.

In the end, I am really grateful to openSUSE for giving me an opportunity to work on such an amazing project with a lot of talented people.

Lets Start Hacking :)