Implementing Accepting and Rejecting Proposals in Open Event Frontend

This blog post will illustrate how to add buttons to accept and reject proposal and making them functional. Sessions tab in event dashboard communicates with the following APIs of Open Event Server.

  • GET                    /v1/sessions
  • PATCH              /v1/sessions
What is meant by accepting or rejecting a session in open event?

Sessions are part of event which include one or many speakers. Speakers can propose one or many sessions for a event. Now it is duty of organizer to accept some proposals and reject others. Open event provides two options to accept or reject a proposal i.e. with email or without email.

For this we need to send a key value pair which includes whether we want to send email or not along with other parameters which include current state of session and other important properties. A typical request to alter state of session looks like this.

{
  "data": {
    "attributes": {
      "title": "Micropython Session",
      "level": 1,
      "starts-at": "2017-06-01T10:00:00.500127+00:00",
      "ends-at": "2017-06-01T11:00:00.500127+00:00",
      "created-at": "2017-05-01T01:24:47.500127+00:00",
      "is-mail-sent": false,
      "send-email": true,
    },
    "type": "session",
    "id": "1"
  }
}
Implementing in frontend

We start by providing two buttons for a pending session. One to accept the session and other to reject the session.

On clicking either accept or reject button we get two options to choose i.e. with email and without email. Depending on what organizer chooses a action is fired from the template and sent to controller. Template code for these buttons looks something like this.

class=“ui vertical compact basic buttons”> {{#unless (eq record.state ‘accepted’)}} {{#ui-dropdown class=‘ui icon bottom right pointing dropdown button’}} class=“green checkmark icon”>

class=“menu”>

class=“item” {{action acceptProposal record true}}>{{t ‘With email’}}

 


class=“item” {{action acceptProposal record false}}>{{t ‘Without email’}}

 

      </div>
    {{/ui-dropdown}}
  {{/unless}}
  {{#unless (eq record.state 'rejected')}}
    {{#ui-dropdown class='ui icon bottom right pointing dropdown button'}}
      <i class="red remove icon"></i>

class=“menu”>

class=“item” {{action rejectProposal record true}}>{{t ‘With email’}}

 


class=“item” {{action rejectProposal record false}}>{{t ‘Without email’}}

 

      </div>
    {{/ui-dropdown}}
  {{/unless}}
</div>

We can see that for with email button we trigger accept proposal button with two parameters record and true. Record contains the instance of session and true signifies that we are sending email. Similar is the case with without email button. Controller for these actions looks something like this.

acceptProposal(session, sendEmail) {
      session.set('sendEmail', sendEmail);
      session.set('state', 'accepted');
      session.set('isMailSent', sendEmail);
      this.set('isLoading', true);
      session.save()
        .then(() => {
          sendEmail ? this.notify.success(this.get('l10n').t('Session has been accepted and speaker has been notified via email.'))
            : this.notify.success(this.get('l10n').t('Session has been accepted'));
        })
        .catch(() => {
          this.notify.error(this.get('l10n').t('An unexpected error has occurred.'));
        })
        .finally(() => {
          this.set('isLoading', false);
        });
    },
    rejectProposal(session, sendEmail) {
      session.set('sendEmail', sendEmail);
      session.set('state', 'rejected');
      session.set('isMailSent', sendEmail);
      this.set('isLoading', true);
      session.save()
        .then(() => {
          sendEmail ? this.notify.success(this.get('l10n').t('Session has been rejected and speaker has been notified via email.'))
            : this.notify.success(this.get('l10n').t('Session has been rejected'));
        })
        .catch(() => {
          this.notify.error(this.get('l10n').t('An unexpected error has occurred.'));
        })
        .finally(() => {
          this.set('isLoading', false);
        });
    }

For accepting with email we set sendEmail field to true and send the query to server. Similarly for reject proposal action we follow same procedure.

Conclusion

Implementing buttons like these, and defining proper actions like these we are able to change the state of session with options to send email or not.

Resources

Continue ReadingImplementing Accepting and Rejecting Proposals in Open Event Frontend

Adding Online Payment Support in Online Event Frontend via Stripe

Open Event Frontend involves ticketing system which supports both paid and free tickets. To buy a paid ticket Open Event provides several options such as debit card, credit card, cheque, bank transfer and onsite payments. So to add support for debit and credit card payments Open Event uses stripe checkout. Using stripe users can enter their card details and pay for their ticket.

Given below are some steps which are to be followed for successfully charging a user for ticket using his/her card.

  • We get publishable key for organizer’s stripe account using OAuth. See this blog.
  • We render stripe checkout button using stripe publishable key. This helps us identify which user to credit after payment.
  • After clicking checkout button user is prompted to enter his/her card details and verify payment.
  • After user’s verification stripe generates a payment token is which is used by open event frontend to charge the user for stipulated amount.
  • We send this token to open event server which processes the token and charge the user.
  • We get error or success message from open event server as per the process outcome.

To render the stripe checkout button we use ember-cli-stripe. Below is the code which helps us to understand how stripe checkout button is rendered.

// app/templates/orders/placed.hbs 

{{stripe-checkout
    locale='auto'
    name="Open Event"
    description=paymentDescription
    amount=paymentAmount
    key=model.event.stripeAuthorization.stripePublishableKey
    onToken=(action "processStripeToken")
    onClosed=(action "checkoutClosed")
    onOpened=(action "checkoutOpened")
}}

 

Full code can be seen here.

We see that we pass different parameters to stripe button which helps stripe identify how to render the button and what information to display. We have also passed the actions onToken(), onClosed() and onOpened(). All these actions are triggered at different instances based on what event occurs.

onToken(): This action is triggered when user has verified his/her purchase and we stripe has generated the payment token. Stripe passes the token back to client (open event frontend server) to process. We have handled this error via different name “processStripeToken()”. We will see cose for these actions below.

onClosed(): This action is called when checkout prompt is closed. We have not used this action in open event frontend. But this can be used to trigger some event in case your application need some action when checkout prompt is closed.

onOpened(): This action is called when checkout prompt is opened. We have not used this action in open event frontend. But this can be used to trigger some event in case your application need some action when checkout prompt is opened.

Code for these actions are given below. Full code file can be seen here.

//  app/controllers/orders/placed.js 

processStripeToken(token) {
   // Send this token to server to process payment
   let order = this.get('model');
   let chargePayload = {
     'data': {
       'attributes': {
         'stripe'            : token.id,
         'paypal_payer_id'   : null,
         'paypal_payment_id' : null
       },
       'type': 'charge'
     }
   };
   let config = {
     skipDataTransform: true
   };
   chargePayload = JSON.stringify(chargePayload);
   return this.get('loader').post(`orders/${order.identifier}/charge`, chargePayload, config)
     .then(charge => {
       if (charge.data.attributes.status) {
         this.get('notify').success(charge.data.attributes.message);
         this.transitionToRoute('orders.view', order.identifier);
       } else {
         this.get('notify').error(charge.data.attributes.message);
       }
     });
 }

 

In above code snippet for processStipeToken() we are processing the stripe payment token received from stripe after user verifies his/her payment. We pass this token to charge endpoint of open event server. After charging the user server send a response which is displayed on frontend.

In this way we achieve the functionality of adding stripe payment support in open event frontend. Please follow the links below for further clarification and detailed overview.

Resources:
Continue ReadingAdding Online Payment Support in Online Event Frontend via Stripe

Adding an Edit Route for Access Codes in Open Event Frontend

This blog post will illustrate how to add edit route to access code to allow organizers editing an access code. Editing access codes deals with the following API on Open Event Server.

PATCH          /v1/access-codes/{id}

First of all we need to add a route to allow editing of access codes. Our route will be /events/{event_id}/tickets/access-codes/edit/{access_code_id}. To generate a new route we need to run the command

ember g route events/view/tickets/access-codes/edit

This will generate new routes files and templates. Also this will add this route in router.js. In router.js we need to specify what we are passing as a parameter to route. For this we specify access_code_id to let ember know that this parameter will be passed with the URL. This is done so as to know which access code to update. Our route should look something like this /events/{event_id}/tickets/access-codes/edit/{access_code_id}. Final router.js file for access-codes part is given below:

//  app/router.js
 
this.route('access-codes', function() {
   this.route('list', { path: '/:access_status' });
   this.route('create');
   this.route('edit', { path: '/edit/:access_code_id' });
});

 

Next we need to pass model (data) to our edit route template. In our model we will be looking for a particular access code with an id and event tickets. After we get our event tickets, we then look for the event tickets which are already present in that access code. This is done so as to check the tickets in the template which are already present in that access code. So for this in afterModel hook we loop over all event tickets and whichever ticket is included in the access code tickets array we mark its isChecked property as true. This helps us to mark those tickets as checked in multiple select checkboxes of template.

// app/routes/events/view/tickets/access-codes/edit.js

model(params) {
   return RSVP.hash({
     accessCode : this.store.findRecord('access-code', params.access_code_id, {}),
     tickets    : this.modelFor('events.view').query('tickets', {})
   });
 },

 async afterModel(model) {
   let tickets = await model.accessCode.tickets;
   let allTickets = model.tickets;
   allTickets.forEach(ticket => {
     if (tickets.includes(ticket)) {
       ticket.set('isChecked', true);
     } else {
       ticket.set('isChecked', false);
     }
   });

 

The information about multiple select checkboxes in frontend has been discussed in this blog post. Now after we are done setting our edit route we need to redirect user to edit page when he/she clicks on the edit button in access code list. For this we define the necessary actions in template which will be triggered when user clicks on the icon. Code for the edit icon in access code list is given below.

// templates/components/ui-table/cell/events/view/tickets/access-codes/cell-actions.hbs

class="ui vertical compact basic buttons"> {{#ui-popup content=(t 'Edit') click=(action editAccessCode record.id) class='ui icon button' position='left center'}} class="edit icon"> {{/ui-popup}}

 

The editAccessCode action looks something like this.

// controller/events/view/tickets/access-codes/edit.js

editAccessCode(id) {
     this.transitionToRoute('events.view.tickets.access-codes.edit', id);
}

 

After clicking on the edit icon user is redirected to edit route where he/she can edit access code choosen. We use the same component that we chose for creating access code. To know more about create access code template component refer to this blog. Finally when saving the edited access code we call save action. This action is defined in the controllers. The action looks something like this.

// controllers/events/view/tickets/access-codes/edit.js

export default Controller.extend({
 actions: {
   save(accessCode) {
     accessCode.save()
       .then(() => {
         this.get('notify').success(this.get('l10n').t('Access code has been successfully updated.'));
         this.transitionToRoute('events.view.tickets.access-codes');
       })
       .catch(() => {
         this.get('notify').error(this.get('l10n').t('An unexpected error has occured. Discount code cannot be created.'));
       });
   }
 }
});

 

After the access code is saved. We redirect user back to access code list.

Resources

Continue ReadingAdding an Edit Route for Access Codes in Open Event Frontend

Integrating Orders API to Allow User Select Tickets for Placing Order in Open Event Frontend

In Open Event Frontend organizer has option to sell tickets for his event. Tickets which are available to public are listed in public page of event for users to buy. In this blog post we will learn how to integrate orders API and manage multiple tickets of varying quantity under an order.

For orders we mainly interact with three API endpoints.

  1. Orders API endpoint
  2. Attendees API endpoint
  3. Tickets API endpoint

Orders and attendees have one to many relationship and similarly orders and tickets also have one to many relationship. Every attendee is related to one ticket. In simple words one attendee has one ticket and one order can contain many tickets of different quantity each meant for different attendee.

// routes/public/index.js

order: this.store.createRecord('order', {
  event     : eventDetails,
  user      : this.get('authManager.currentUser'),
  tickets   : [],
  attendees : []
})

 

We need to create instance of order model to fill in data in that record. We do this in our routes folder of public route. Code snippet is given below.

We create a empty array for tickets and attendees so that we can add their record instances as relationship to order.

As given in screenshot we have a dropdown for each ticket to select quantity of each ticket. To allow user select quantity of a ticket we use #ui-dropdown component of ember-semantic-ui in our template. The code snippet of that is given below.

// templates/components/public/ticket-list.js

{{#ui-dropdown class='compact selection' forceSelection=false onChange=(action 'updateOrder' ticket) as |execute mapper|}}
  {{input type='hidden' id=(concat ticket.id '_quantity') value=ticket.orderQuantity}}
    <i class="dropdown icon"></i>
    
class="default text">0
class="menu">
class="item" data-value="{{map-value mapper 0}}">{{0}}
{{#each (range ticket.minOrder ticket.maxOrder) as |count|}}
class="item" data-value="{{map-value mapper count}}">{{count}}
{{/each}} </div> {{/ui-dropdown}}

 

For every change in quantity of ticket selected we call a action named updateOrder. The code snippet for this action is given below.

// components/public/ticket-list.js

updateOrder(ticket, count) {
      let order = this.get('order');
      ticket.set('orderQuantity', count);
      order.set('amount', this.get('total'));
      if (count > 0) {
        order.tickets.addObject(ticket);
      } else {
        if (order.tickets.includes(ticket)) {
          order.tickets.removeObject(ticket);
        }
      }
    },

 

Here we can see that if quantity of selected ticket is more than 0 we add that ticket to our order otherwise we remove that ticket from the order if it already exists.

Once user selects his tickets for the order he/she can order the tickets. On clicking Order button we call placeOrder action. With help of this we add all the relations and finally send the order information to the server. Code snippet is given below.

// components/public/ticket-list.js
    
placeOrder() {
   let order = this.get('order');
   let event = order.get('event');
   order.tickets.forEach(ticket => {
     let attendee = ticket.orderQuantity;
     let i;
     for (i = 0; i < attendee; i++) {
       order.attendees.addObject(this.store.createRecord('attendee', {
         firstname : 'John',
         lastname  : 'Doe',
         email     : '[email protected]',
         event,
         ticket
       }));
     }
   });
   this.sendAction('save');
 }

 

Here for each ticket placed under an order we create a dummy attendee related to ticket and event. And then we call save action to save all the models. Code snippet for save is given:

actions: {
    async save() {
      try {
        this.set('isLoading', true);
        let order = this.get('model.order');
        let attendees = order.get('attendees');
        await order.save();
        attendees.forEach(async attendee => {
          await attendee.save();
        });
        await order.save()
          .then(order => {
            this.get('notify').success(this.get('l10n').t('Order created.'));
            this.transitionToRoute('orders.new', order.id);
          });
      } catch (e) {
        this.get('notify').error(this.get('l10n').t('Oops something went wrong. Please try again'));
      }
    }
  }

 

Here we finally save all the models and transition to orders page to enable user fill the attendees details.

Resources:
Continue ReadingIntegrating Orders API to Allow User Select Tickets for Placing Order in Open Event Frontend

Modifying Tickets API in Open Event Server to Return Hidden Tickets Only for Organizers and Admins

This blog article will illustrate how we can modify the permissions settings for an API to enable different kind of responses to users with different level of permissions. In this article we will discuss these changes with respect to Tickets API.

Initially we had a query where we were returning only those tickets who were set to be visible by the admin. Query for this was:

class TicketList(ResourceList):
   """
   List Tickets based on different params
   """
   def before_get(self, args, view_kwargs):
       """
       before get method to get the resource id for assigning schema
       :param args:
       :param view_kwargs:
       :return:
       """
       if view_kwargs.get('ticket_tag_id') or view_kwargs.get('access_code_id') or         view_kwargs.get('order_identifier'):
           self.schema = TicketSchemaPublic

   def query(self, view_kwargs):
       """
       query method for resource list
       :param view_kwargs:
       :return:
       """


       query_ = self.session.query(Ticket).filter_by(is_hidden=False)

 

Problem with this query was that this returned same response irrespective of who is logged in. Hence even the organizers were not able to modify hidden tickets because they were not returned by server.

Solution to this problem was to provide hidden tickets only to those who are organizer or are admin/super admins. For this we used the JWT token that was being sent from frontend in request headers for each authenticated request that was being made from frontend.

We modified the code to something like this:

class TicketList(ResourceList):
   """
   List Tickets based on different params
   """
   def before_get(self, args, view_kwargs):
       """
       before get method to get the resource id for assigning schema
       :param args:
       :param view_kwargs:
       :return:
       """
       if view_kwargs.get('ticket_tag_id') or view_kwargs.get('access_code_id') or view_kwargs.get('order_identifier'):
           self.schema = TicketSchemaPublic

   def query(self, view_kwargs):
       """
       query method for resource list
       :param view_kwargs:
       :return:
       """

       if 'Authorization' in request.headers:
           _jwt_required(current_app.config['JWT_DEFAULT_REALM'])
           if current_user.is_super_admin or current_user.is_admin:
               query_ = self.session.query(Ticket)
           elif view_kwargs.get('event_id') and has_access('is_organizer', event_id=view_kwargs['event_id']):
               query_ = self.session.query(Ticket)
           else:
               query_ = self.session.query(Ticket).filter_by(is_hidden=False)
       else:
           query_ = self.session.query(Ticket).filter_by(is_hidden=False)

 

Here we added some conditions which were used to check permission level of logged in user. After picking JWT token from request headers we check if the user was admin or super_admin, then we return all the tickets without any condition. Then we also check if the logged in user was organizer of event then also we send all the tickets without any conditions.

However if request comes from unauthenticated users (without valid token) or users with normal privileges, then we returned tickets whose isHidden property was set to False. The functions such as is_organizer and is_super_admin acted as helpers as they were imported from other helper files where they were defined.

Resources

Continue ReadingModifying Tickets API in Open Event Server to Return Hidden Tickets Only for Organizers and Admins

How We Implement Custom Forms for Sessions and Speaker Form in Open Event Frontend

In this blog we will see the implementation of custom form for session and speakers form. Since every event organiser requires different fields required to be filled by speakers for their sessions, for ex. Some event organiser may need GitHub profile whereas other may need LinkedIn profile so, we implemented custom form for session and speaker form in Open Event Frontend so that every organiser can choose fields he/she requires to be filled by his speakers who are filling their proposal. Custom form allows following features:

  1. Allows organiser to choose whether he wants a particular field or not.
  2. Organiser can make a field compulsory, so that no speaker can submit his proposal without filling that field.

So, to get started we define our getCustomForm() method in mixins and it looks something like this:

import Mixin from '@ember/object/mixin';
import MutableArray from '@ember/array/mutable';

export default Mixin.create(MutableArray, {

 getCustomForm(parent) {
   return [
     this.store.createRecord('custom-form', {
       fieldIdentifier : 'title',
       form            : 'session',
       type            : 'text',
       isRequired      : true,
       isIncluded      : true,
       isFixed         : true,
       event           : parent
     }),
     this.store.createRecord('custom-form', {
       fieldIdentifier : 'subtitle',
       form            : 'session',
       type            : 'text',
       isRequired      : false,
       isIncluded      : false,
       event           : parent
     }),
     this.store.createRecord('custom-form', {
       fieldIdentifier : 'shortAbstract',
       form            : 'session',
       type            : 'text',
       isRequired      : false,
       isIncluded      : true,
       event           : parent
     }),

...

 

Here we define all the possible fields with their properties. Every field has different properties that enables us to identify whether to choose or reject them. So to enable this these fields to be chosen by organiser we need to feed them into model.

In our session-speakers-step.js in components we assign these fields to our model thorugh this:

didInsertElement() {
   if (this.get('data.event.customForms')&&!his.get('data.event.customForms.length')) {
     this.set('data.event.customForms', this.getCustomForm(this.get('data.event')));
   }
}

 

This hook gets called when our component is rendered and custom form fields gets assigned to data.event.customForms in our model.

In our handlebars template we create sliders to enable organiser to choose whether he wants to enable a field or not.

In our template logic we write a loop that renders these sliders for each fields and manipulate them as organiser slides any slider for a field. Let’s take a look at the template code block:

       <tbody>
           {{#each customForm.session as |field|}}
             <tr class="{{if field.isIncluded 'positive'}}">
               <td class="{{if device.isMobile 'center' 'right'}} aligned">
                 <label class="{{if field.isFixed 'required'}}">
                   {{field.name}}
                 </label>
               </td>
               <td class="center aligned">
                 {{ui-checkbox class='slider'
                               checked=field.isIncluded
                               disabled=field.isFixed
                               onChange=(action (mut field.isIncluded))
                               label=(if device.isMobile (t 'Include'))}}
               </td>
               <td class="center aligned">
                 {{ui-checkbox class='slider'
                               checked=field.isRequired
                               disabled=field.isFixed
                               onChange=(action (mut field.isRequired))
                               label=(if device.isMobile (t 'Require'))}}
               </td>
             </tr>
           {{/each}}
         </tbody>

 

Every slider has a action attached to it that manipulates a property of the custom for and on proceeding it saves the custom form model to server.

Later on when rendering for for speaker we fetch details from server about which fields are required or not.

Resources

Continue ReadingHow We Implement Custom Forms for Sessions and Speaker Form in Open Event Frontend

How RSVP Handles Promises in Open Event Frontend

This blog post illustrates how to manage multiple promises simultaneously using a library known as RSVP in Open Event frontend.

What are Promises?

Promises are used to manage synchronous calls in javascript. Promises represent a value/object that may not be available yet but will become available in near future. To quote from MDN web docs:

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

What about RSVP?

Rsvp is a lightweight library used to organize asynchronous code. Rsvp provides several ways to handle promises and their responses. A very simple promise implementation using rsvp looks something like this.

var RSVP = require('rsvp');

var promise = new RSVP.Promise(function(resolve, reject) {
  // succeed
  resolve(value);
  // or reject
  reject(error);
});

promise.then(function(value) {
  // success
}).catch(function(error) {
  // failure
});

 

It’s simple, right? So, what it is doing is after it defines a promise it assumes two possible states of a promise which are resolve or reject and after promise has completed it executes the respective function.

Use in Open Event Frontend?

Almost all calls to open event server APIs are done asynchronously. One of the most significant use of rsvp comes when handling multiple promises in frontend and we want all of them to be evaluated at together. Unlike normal promises where each promises resolved or rejected individually, rsvp provides a promise.all() method which accepts array of promises and evaluates all at once. It then calls resolve or reject based on the status of all promises. A typical example where we use promise.all() is given here.

import Controller from '@ember/controller';
import RSVP from 'rsvp';
import EventWizardMixin from 'open-event-frontend/mixins/event-wizard';

export default Controller.extend(EventWizardMixin, {
 actions: {
   save() {
     this.set('isLoading', true);
     this.get('model.data.event').save()
       .then(data => {
         let promises = [];
         promises.push(this.get('model.data.event.tickets').toArray().map(ticket => ticket.save()));
         promises.push(this.get('model.data.event.socialLinks').toArray().map(link => link.save()));
         if (this.get('model.data.event.copyright.licence')) {
           let copyright = this.setRelationship(this.get('model.data.event.copyright.content'), data);
           promises.push(copyright.save());
         }
         if (this.get('model.data.event.tax.name')) {
           let tax = this.setRelationship(this.get('model.data.event.tax.content'), data);
           if (this.get('model.event.isTaxEnabled')) {
             promises.push(tax.save());
           } else {
             promises.push(tax.destroyRecord());
           }
         }
         RSVP.Promise.all(promises)
           .then(() => {
             this.set('isLoading', false);
             this.get('notify').success(this.get('l10n').t('Your event has been saved'));
             this.transitionToRoute('events.view.index', data.id);
           }, function() {
             this.get('notify').error(this.get('l10n').t('Oops something went wrong. Please try again'));
           });
       })
       .catch(() => {
         this.set('isLoading', false);
         this.get('notify').error(this.get('l10n').t('Oops something went wrong. Please try again'));
       });
   },
}

 

Here we made array of promises and then pushed each of the promises to it. Then at the end used this array of promises in RSVP.promise.all() which then evaluated it based on success or failure of the promises.

Resources:
Continue ReadingHow RSVP Handles Promises in Open Event Frontend

Different Text Color On Each Line In Badgeyay

In this blog post I am going to explain about how to create different text color for each line in badges generation in Badgeyay. As the system now has option for different badge size and paper size, currently the system sets same color for each line by mutating the fill parameter in the SVG. The main challenge in mutating the SVG parameter for each badge is the Id. The ID identifies the element, in our case text, and gives access to iterate the SVG through libraries like lxml. So for implementing this feature we first need to manipulate the SVG and assign id’s to the text tag so that it can be easily manipulated through the algorithm.

Procedure

  1. Manipulating the text tag in SVG and assigning a proper ID according to the logic for iteration in the function.
<text

     id=“Person_color_1_1”

     ….>

Person_1_1

</text>

The id of the person in first badge and first line is represented as Person_color_1_1, where the first number denotes the number of badge and second number denotes the line number.

  1. Creating a class for the dimensions of the badges
class Dimen(object):
  def __init__(self, badges, badgeSize, paperSize):
      self.badges = badges
      self.badgeSize = badgeSize
      self.paperSize = paperSize
  1. Creating an initialiser function that stores the dimension objects
badge_config = {}


def init_dimen():
  paper_sizes = [‘A2’, ‘A3’, ‘A4’]
  for paper in paper_sizes:
      if paper == ‘A2’:
          badge_config.__setitem__(paper, {‘4×3’: Dimen(18, ‘4×3’, paper)})
          badge_config[paper][‘4.5×4’] = Dimen(15, ‘4.5×4’, paper)
      elif paper == ‘A3’:
          badge_config.__setitem__(paper, {‘4×3’: Dimen(8, ‘4×3’, paper)})
          badge_config[paper][‘4.5×4’] = Dimen(6, ‘4.5×4’, paper)
      elif paper == ‘A4’:
          badge_config.__setitem__(paper, {‘4×3’: Dimen(6, ‘4×3’, paper)})
          badge_config[paper][‘4.5×4’] = Dimen(2, ‘4.5×4’, paper) 
  1. Selecting the dimension config based on the parameters passed in the function.
dimensions = badge_config[paper_size][badge_size]
  1. Looping criteria is to loop through the number of badges mentioned in the dimension config and through the number of lines which will be five.
for idx in range(1, dimensions.badges + 1):

          for row in range(1, 6):
  1. Selecting the text element with the ID as provided above.
_id = ‘Person_color_{}_{}’.format(idx, row)
              path = element.xpath((“//*[@id='{}’]”).format(_id))[0]
  1. Fill the text color argument of the selected object by changing the value of fill.
style_detail[6] = “fill:” + str(fill[row])

That’s it and now when the loop runs each line will have its individual color as passed in the function. The choice of color is passed as the list named fill.

Resources

Continue ReadingDifferent Text Color On Each Line In Badgeyay

Loading Default System Image of Event Topic on Open Event Server

In this blog, we will talk about how to add feature of loading system image of event topic from server to display it on Open Event Server. The focus is on adding a helper function to create system image and loading that local image onto server.

Helper function

In this feature, we are providing feature of addition of loading default system image if user doesn’t provides that.

  1. First we get a suitable filename for a image file using get_file_name() function.
  2. After getting filename, we check if the url provided by user is a valid url or not.
  3. If the url is invalid then we use the default system image as the image of that particular event topic.
  4. After getting the local image then we read that image, if the given image file or the default image is not readable or gives IOError then we send a message to the user that Image url is invalid.
  5. After successful reading of image we upload the image to event_topic directory in static directory of the project.
  6. After uploading of this image we get a local URL which shows where is the image is stored. This path is stored into database and finally we can display this image.

Resources

Continue ReadingLoading Default System Image of Event Topic on Open Event Server

Adding Custom System Roles API on Open Event Server

In this blog, we will talk about how to add API for accessing the Custom System Roles on Open Event Server. The focus is on Schema creation and it’s API creation.

Schema Creation

For the CustomSystemRoleSchema, we’ll make our Schema as follows

Now, let’s try to understand this Schema.

In this feature, we are providing Admin the rights to get and create more system roles.

  1. First of all, we are provide the two fields in this Schema, which are id and name.
  2. The very first attribute id should be of type string as it would have the identity which will auto increment when a new system role is created. Here dump_only means that this value can’t be changed after the record is created.
  3. Next attribute name should be of string type and it will contain the name of new custom system role. This attribute is required in a custom_system_roles table.

API Creation

For the Custom System Roles, we’ll make our API as follows

Now, let’s try to understand this Schema.

In this API, we are providing Admin the rights to set Custom System roles.

  1. CustomSystemRoleList inherits ResourceList which will give us list of all the custom system roles in the whole system.
  2. CustomSystemRoleList has a decorators attribute which gives the permission of POST request to only admins of the system.
  3. CustomSystemRoleDetail inherits ResourceDetail which will give the details of a CustomSystemRole object by id.
  4. CustomSystemRoleDetail has a decorators attribute which gives the permission of PATCH and DELETE requests to only admins of the system.

So, we saw how Custom System Role Schema and API is created to allow users to get it’s values and Admin users to update and delete it’s record.

Resources

Continue ReadingAdding Custom System Roles API on Open Event Server