FOSSASIA Summit 2021 Call for Speakers and Projects

The FOSSASIA Summit 2021 will take place ONLINE this year. The event will spread out over the week of March 13 – 21 and will run on our own open source virtual event platform ‘eventyay’. 

Speakers interested to submit a talk, panel or workshop please propose your session before 4th February (soft deadline). We want to learn from you how to solve the challenges of our time with Open Technologies! 

At the event we are connecting local hubs, makerspaces, clubs and university IT groups across Asia. Please fill in this form to become a community hub partner and get listed on the event site.


Topics

The current situation around the world shows us that open global collaboration is the way to solve our problems. Now we would like you to share your hands-on examples at the event of topics such as how to:

  • Take on the fight against COVID-19 with open health technologies
  • Solve everyday problems with AI
  • Tackle climate change with an open source approach
  • Create open hardware solutions for science and Biohacking
  • Run DevOps in a distributed team in home office
  • Implement continuous delivery and sovereign cloud stacks with diverse tools
  • Establish a friendly, welcoming and collaborative project culture
  • Ensure digital sovereignty and independent data governance
  • Get privacy and security right
  • Customize Linux for lightweight hardware and special use cases
  • And what are best practices for open access education

.. and many more topics about Databases, Web and Mobile Technologies, Robotics, Blockchain, Design and Compliance. Please find the complete list of tracks on the event site and submit your proposal.

Important Dates

  • CfS soft deadline: 4 February 2021 (submissions receive priority)
  • Late submission cut off date: 11 February 2021
  • Event dates: 13 – 21 March 2021
  • Notification of acceptance: On an ongoing basis

Sessions and Slots

Talks

Talk slots are 15 minutes, 25 minutes or 40 minutes long these include time for questions and answers. We recommend to reserve at least a third of the time for questions. Shorter sessions are preferred to avoid online fatigue of the audience.

Panels

Panels are sessions with at least two panelists who discuss a topic and provide insights. Available slots are 55 minutes.

Workshops

Workshop options are 90 minutes, 2 hours or 3 hours. We are looking for interactive workshops where participants can actively engage in.

Lightning talks

You have some interesting ideas but do not want to submit a full talk? We suggest you go for a lightning talk which is a 5 minutes slot to present your idea or project.

Virtual exhibition

We offer virtual exhibition rooms for companies, projects, online installations, team gatherings and other fun activities. We are curious to know what you would like to show. Please add details in the submission form.

To Know

  • This year summit will take place online.
  • Speakers will conduct their sessions live to provide an interactive environment
  • Speakers can deliver sessions in English or a language of their choice.
  • Q&As and interaction among participants are highly encouraged.
  • Submissions for hands-on workshops and panel discussions are preferable as they provide more interactive opportunities.

Publication

Audio and video recordings of the lectures will be published in various formats under the Creative Commons Attribution 4.0 International (CC BY 4.0) license. This license allows commercial use by media institutions as part of their reporting. If you do not wish for material from your lecture to be published or streamed, please let us know in your submission.

Links

FOSSASIA Summit: summit.fossasia.org

FOSSASIA Videos: Youtube FOSSASIA

FOSSASIA on Twitter: twitter.com/fossasia

Continue Reading FOSSASIA Summit 2021 Call for Speakers and Projects

FOSSASIA Summit 2020 Takes Places as Online and Offline Event

Due to the Corona crisis it is clear that events like the FOSSASIA Summit cannot be run in the usual way with large crowds. Therefore this year the FOSSASIA Summit will only be possible as a smaller gathering with social distancing in Singapore and online interactions from Thursday, March 19 – Saturday, March 21. 

Even with travel restrictions in place a number of speakers are in Singapore and expressed their wish sharing their knowledge and the FOSSASIA team is working hard to facilitate this in a safe space offline and online. Due to ongoing changes we will conduct the event with both unscheduled and scheduled sessions. The program will be updated continuously here.

The Lifelong Learning Institute, our host and co-organizer, adjusted the venue to ensure the safety and health of all. To participate on-premise you need to pass a screening test and follow directions for hygiene measures. The sign up is here

Singapore has an outstanding record seen internationally as a gold standard when it comes to cleanliness, hygiene and health. Additional measures in the LLI include providing entrance screening tests, social distancing, using open spaces, reducing the use of mics and mic disinfection, avoiding close group photos. Please find a list of measures here.

The events of our time show more than ever that we need to collaborate to solve the world’s problems such as climate change, global health issues, poverty and economic challenges. The FOSS/Open Source community has proven that we are able to overcome differences and work together across countries and cultures. It is important that we stay connected and continue our work be it offline or online. To connect virtually during the FOSSASIA Summit you can join us on these channels:

We will share more details about sessions in the upcoming days. Furthermore, we are planning additional online events at a later time this year. Let’s continue and build a better world through learning and sharing where-ever and however we can!

We would like to thank everyone who supported us throughout these challenges around the event – our speakers, friends, supporters, and partners like Google, Facebook, Arm, and Elastic.

We hope to stay connected. All the best and stay healthy!

FOSSASIA Presentations
FOSSASIA Videographers
Continue Reading FOSSASIA Summit 2020 Takes Places as Online and Offline Event

Implement JWT Refresh token in Open Event Attendee App

In open event attendee android app earlier only access token is used, which causes HTTP 401 many time due to expiry of the token. It needs to re sign-in for the user. Now we have implemented refresh token authorization with the open event server using retrofit and OkHttp. Retrofit is one of the most popular HTTP client for Android. When calling API, we may require authentication using a token. Usually, the token is expired after a certain amount of time and needs to be refreshed using the refresh token. The client would need to send an additional HTTP request in order to get the new token. Imagine you have a collection of many different APIs, each of them requires token authentication. If you have to handle refresh token by modifying your code one by one, it will take a lot of time and of course, it’s not a good solution. In this blog, I’m going to show you how to handle refresh token on each API calls automatically if the token expires.

  • How refresh token works?
  • Add authenticator to OkHttp
  • Network call and handle response
  • Conclusion
  • Resources 

Let’s analyze every step in detail.

How Refresh Token Works?

Whether tokens are opaque or not is usually defined by the implementation. Common implementations allow for direct authorization checks against an access token. That is, when an access token is passed to a server managing a resource, the server can read the information contained in the token and decide itself whether the user is authorized or not (no checks against an authorization server are needed). This is one of the reasons tokens must be signed (using JWS, for instance). On the other hand, refresh tokens usually require a check against the authorization server. 

Add Authenticator to OkHTTP

OkHttp will automatically ask the Authenticator for credentials when a response is 401 Not Authorised retrying last failed request with them.

class TokenAuthenticator: Authenticator {

    override fun authenticate(route: Route?, response: Response): Request? {

        // Refresh your access_token using a synchronous api request
        val newAccessToken = service.refreshToken();

        // Add new header to rejected request and retry it
        return response.request().newBuilder()
            .header(AUTHORIZATION, newAccessToken)
            .build()
    }
}

Add the authenticatior to OkHttp:

val builder = OkHttpClient().newBuilder()
            .authenticator(TokenAuthenticator())

Network Call and Handle Response

API call with retrofit:

@POST("/auth/token/refresh")
    fun refreshToken(): Single<RefreshResponse>

Refresh Response:

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class RefreshResponse(
    val refreshToken: String
)

In a Nutshell

Refresh tokens improve security and allow for reduced latency and better access patterns to authorization servers. Implementations can be simple using tools such as JWT + JWS. If you are interested in learning more about tokens (and cookies), check our article here.

Resources

  1. Android – Retrofit 2 Refresh Access Token with OkHttpClient and Authenticator: https://www.woolha.com/tutorials/android-retrofit-2-refresh-access-token-with-okhttpclient-and-authenticator
  2. Refresh Tokens: When to Use Them and How They Interact with JWTs: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

Tags

Eventyay, open-event, FOSSASIA, GSoC, Android, Kotlin, Refresh tokens

Continue Reading Implement JWT Refresh token in Open Event Attendee App

Enable Server Configuration with Okhttp and Retrofit in Open Event Attendee Application

The open event attendee is an android app which allows users to discover events happening around the world using the Open Event Platform. It consumes the APIs of the open event server to get a list of available events and can get detailed information about them.

We are using default API for eventyay app. Server configuration is something when we replace backend API with a new one and perform the same applications with the different server. As it is a fully open-source project on F-droid, so we have enabled the server configuration field for the F-droid build variant. 

  • Retrofit and okhttp for network calls
  • Create a feasible UI and set the link to preferences
  • Create interceptor for changing API URL
  • Add interceptor in okhttp client builder
  • Conclusion
  • Resources 

Let’s analyze every step in detail.

Retrofit and Okhttp for Network Call

Using Retrofit for your Android app’s networking can make your life so much easier. However, Retrofit’s design requires a single Retrofit instance for each API with a different base URL. Consequently, if your app is talking to two or more APIs (under different URLs), you’ll need to deal with at least two Retrofit instances.

Retrofit is a type-safe REST client for Android, Java, and Kotlin developed by Square. The library provides a powerful framework for authenticating and interacting with APIs and sending network requests with OkHttp.

OkHttp communicating with the server- 

Design UI and set the link to preferences with MVVM

Create a simple dialog with a checkbox with default URL and a EditText:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <CheckBox
        android:id="@+id/urlCheckBox"
        android:layout_margin="@dimen/layout_margin_large"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <com.google.android.material.textfield.TextInputLayout           style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
        android:id="@+id/urlTextInputLayout"
        android:layout_margin="@dimen/layout_margin_large"
        android:hint="@string/other_url"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/urlEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

Handle visibility if the dialog and display for only F-droid build:

preferenceScreen.findPreference<PreferenceCategory>(getString(R.string.key_server_configuration))?.isVisible = BuildConfig.FLAVOR == FDROID_BUILD_FLAVOR

Set current API to preference screen:

preferenceScreen.findPreference<Preference>(getString(R.string.key_api_url))?.title =
            settingsViewModel.getApiUrl()

Get API from View model: 

fun getApiUrl(): String {
        return preference.getString(API_URL) ?: BuildConfig.DEFAULT_BASE_URL
    }

Setup alert dialog:

if (preference?.key == getString(R.string.key_api_url)) {
            showChangeApiDialog()
        }
private fun showChangeApiDialog() {
        val layout = layoutInflater.inflate(R.layout.dialog_api_configuration, null)
        layout.urlCheckBox.text = BuildConfig.DEFAULT_BASE_URL

        val dialog = AlertDialog.Builder(requireContext())
            .setView(layout)
            .setPositiveButton(getString(R.string.change)) { _, _ ->
                val url = if (layout.urlCheckBox.isChecked) BuildConfig.DEFAULT_BASE_URL
                                else layout.urlEditText.text.toString()
                if (url === settingsViewModel.getApiUrl()) return@setPositiveButton
                settingsViewModel.changeApiUrl(url)
                view?.snackbar("API URL changed to $url")
                findNavController().popBackStack(R.id.eventsFragment, false)
            }
            .setNegativeButton(getString(R.string.cancel)) { dialog, _ -> dialog.cancel() }
            .setCancelable(false)
            .show()
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false

        layout.urlCheckBox.setOnCheckedChangeListener { _, isChecked ->
            layout.urlTextInputLayout.isVisible = !isChecked
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = isChecked
        }

Set URL to preferences in the view model and end current session:

fun changeApiUrl(url: String) {
        preference.putString(API_URL, url)
        logout()
    }

Create Interceptor to Handle New API URL

Here default API URL is set to the retrofit already: 

Retrofit.Builder()
            .client(get())
            .baseUrl(baseUrl)
            .build()

As we discussed earlier OkHttp handles every network call for the application. So here we track the URL host from the okhttp interceptor. If the URL host is equaled to the default API URL host, then we can say that it is an API call and then we can replace same with the host getting from preferences if it is not null and set the interceptor to okhttp client builder.

Create host selection interceptor class to return interceptor with the API URL:

class HostSelectionInterceptor(private val preference: Preference) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        var original = chain.request()
        val httpUrl = preference.getString(API_URL)?.toHttpUrlOrNull()
        if (original.url.host == BuildConfig.DEFAULT_BASE_URL.toHttpUrlOrNull()?.host && httpUrl != null) {
            val newUrl =
                original.url.newBuilder()
                    .scheme(httpUrl.scheme)
                    .host(httpUrl.host)
                    .port(httpUrl.port)
                    .build()
            original = original.newBuilder()
                .url(newUrl)
                .build()
        }
        return chain.proceed(original)
    }
}

Set the interceptor to okhttp client builder:

val builder = OkHttpClient().newBuilder()
            .addInterceptor(HostSelectionInterceptor(get()))

GIF

In a Nutshell

Server configuration provides better user experience for open-source platform and developer, as they can mention their own server and test it.

Resources

OkHttp client with retrofit: https://futurestud.io/tutorials/retrofit-2-share-okhttp-client-and-converters-between-retrofit-instances

Tags

Eventyay, open-event, OkHttp, Retrofit, FOSSASIA, GSoC, Android, Kotlin

Continue Reading Enable Server Configuration with Okhttp and Retrofit in Open Event Attendee Application

Migration to Model-View-ViewModel Architecture and LiveData in Open Event Organizer App

Open Event Organizer App (Eventyay Organizer App) is the Android app used by event organizers to create and manage events on the Eventyay platform as well as check-in and check-out attendees along with other functionalities. The app used the MVP (Model-View-Presenter) architecture and is being ported to MVVM (Model-View-ViewModel). This article will explain the procedure of migrating MVP to MVVM architecture and implementing LiveData. 

Why migrate to MVVM?

The MVVM architecture is designed to store and manage UI-related data in a lifecycle conscious way. Configuration changes such as screen rotations are handled properly by ViewModels.

Tight Coupling:

The issue of tight coupling is resolved since only the View holds the reference to ViewModel and not vice versa. A single View can hold references to multiple ViewModels.

Testability:

Since Presenters are hard bound to Views, writing unit tests becomes slightly difficult as there is a dependency of a View.

ViewModels are more unit test friendly as they can be independently tested. There is no dependency of the View.

Here, the implementation is being described with the example of About Event module in the Open Event Organizer App.

First step is the creation of a new class AboutEventViewModel which extends ViewModel.

@Binds
@IntoMap
@ViewModelKey(AboutEventViewModel.class)
public abstract ViewModel bindAboutEventViewModel(AboutEventViewModel aboutEventViewModel);

The new ViewModel has to be added to the ViewModelModule:

Constructor for the ViewModel:

@Inject
public AboutEventViewModel(EventRepository eventRepository,  CopyrightRepository copyrightRepository,
DatabaseChangeListener<Copyright> copyrightChangeListener) {
    this.eventRepository = eventRepository;
    this.copyrightRepository = copyrightRepository;
    this.copyrightChangeListener = copyrightChangeListener;

    eventId = ContextManager.getSelectedEvent().getId();
}

We are using Dagger2 for dependency injection. 

LiveData

LiveData is a lifecycle-aware data holder with the observer pattern.

When we have a LiveData object (e.g. list of attendees), we can add some LifecycleOwner (it can be Activity or Fragment) as an observer. Using this:

The Activity or Fragment will remain updated with the data changes.

Observers are only notified if they are in the STARTED or RESUMED state which is also known as the active state. This prevents memory leaks and NullPointerExceptions because inactive observers are not notified about changes.

Now, let’s discuss about the implementation of LiveData. We will create objects of SingleEventLiveData<> class.

private final SingleEventLiveData<Boolean> progress = new SingleEventLiveData<>();
private final SingleEventLiveData<String> error = new SingleEventLiveData<>();
private final SingleEventLiveData<Event> success = new SingleEventLiveData<>();
private final SingleEventLiveData<Copyright> showCopyright = new SingleEventLiveData<>();
private final SingleEventLiveData<Boolean> changeCopyrightMenuItem = new SingleEventLiveData<>();
private final SingleEventLiveData<String> showCopyrightDeleted = new SingleEventLiveData<>();

The functions to get the LiveData objects:

public LiveData<Boolean> getProgress() {
    return progress;
}

public LiveData<Event> getSuccess() {
    return success;
}

public LiveData<String> getError() {
    return error;
}

public LiveData<Copyright> getShowCopyright() {
    return showCopyright;
}

public LiveData<Boolean> getChangeCopyrightMenuItem() {
    return changeCopyrightMenuItem;
}

public LiveData<String> getShowCopyrightDeleted() {
    return showCopyrightDeleted;
}

Now, we can remove getView() methods and instead, these objects will be used to call various methods defined in the fragment.

Let’s discuss the changes required in the AboutEventFragment now.

The Fragment will have ViewModelProvider.Factory injected.

@Inject
ViewModelProvider.Factory viewModelFactory;

Declare an object of the ViewModel.

private AboutEventViewModel aboutEventViewModel;

Then, in onCreateView(), viewModelFactory will be passed to the ViewModelProviders.of() method as the factory, which is the second parameter.

aboutEventViewModel = ViewModelProviders.of(this, viewModelFactory).get(AboutEventViewModel.class);

Replace all references to the Presenter with references to the ViewModel.

Add the Fragment as an observer to the changes by adding the following in the onStart() method:

aboutEventViewModel.getProgress().observe(this, this::showProgress);
aboutEventViewModel.getSuccess().observe(this, this::showResult);
aboutEventViewModel.getError().observe(this, this::showError);
aboutEventViewModel.getShowCopyright().observe(this, this::showCopyright);
aboutEventViewModel.getChangeCopyrightMenuItem().observe(this, this::changeCopyrightMenuItem);
aboutEventViewModel.getShowCopyrightDeleted().observe(this, this::showCopyrightDeleted);

Two parameters are passed to the observe() method  –  first one is LifecycleOwner, which is our Fragment in this case. The second one is a callback along with a parameter and is used to call the required method.

With this, the implementation of MVVM and LiveData is brought to completion.

Resources:

Documentation: ViewModel, LiveData

Further reading:

Open Event Organizer App: Project repo, Play Store, F-Droid

Continue Reading Migration to Model-View-ViewModel Architecture and LiveData in Open Event Organizer App

Working with Route Hooks in Badgeyay

Badgeyay is an open source project developed by FOSSASIA Community to generate badges for conferences and events through a simple user interface.

In this post I am going to explain about the route lifecycle hooks in ember and how we have utilized one lifecycle component to reset the controller state in badge generation form. In Ember every entity has some predefined set of methods, that it goes through the existence of the application. Route is not different from it. Our main goal is to restore the state of the controller every time we entered into a route, so that we receive a clean and new instance and not the previous state. The hook that fits in the situation is setupController(). This method is called after model() hook to set the controller state in the route. We will restore the variables in the controller here in this method to reset it to original state. This will help in removing the messages and progress on the previous state of the page on a new visit.

Procedure

  1. Open the route, where we want to override the hook, and create a method setupController() this will call the base hook and override its behaviour.
setupController(controller, model) {
  this._super(…arguments);
  set(controller, ‘defImages’, model.def_images);
  set(controller, ‘user’, model.user);
  this.set(‘controller.badgeGenerated’, false);
  this.set(‘controller.showProgress’, false);
}

 

As we can see in the method, it first initialises the super constructor and then we are writing the logic for the reset state. This will reset the badgeGenerated and showProgress variable in the controller to mentioned values.

  1. Getting the generated badge link from the last promise resolved to set the value of the variable in the controller action.
sendBadge(badgeData) {

        this.set(‘badgeGenerated’, true);

  },

 

This will set the value of the variable to the received object from backend.

  1. Showing the content in frontend based on the values of the variable. When we initially visit the route it is set to as false in the setupController() hook and is changed later on through some promise resolvement in an action.
{{#if badgeGenerated}}

 . . .


{{/if}}

 

This content will be only be shown in the present state and when the user revisits the route the state will be resetted.

Pull Request for the respective issue – https://github.com/fossasia/badgeyay/pull/1313

Resources

Continue Reading Working with Route Hooks in Badgeyay

Adding Marketer and Sales Admin Events Relationship with User on Open Event Server

In this blog, we will talk about how to add API for adding and displaying events in with a user acts as a Marketer and/or Sales Admin on Open Event Server. The focus is on Model Updation and Schema updation of User.

Model Updation

For the Marketer and Sales Admin events, we’ll update User model as follows

Now, let’s try to understand these relationships.

In this feature, we are providing user to act as a marketer and sales admin for a event.

  1. Both the relationships will return the events in which the user is acting as a Marketer and/or Sales Admin.
  2. There are two custom system roles in model CustomSysRole which are Marketer and Sales Admin. A user can act as these custom system roles with respect to an event.
  3. In this relationship, we will return those events from UserSystemRole model in which a user is acting as Marketer Custom System Role and Sales Admin Custom System Role.
  4. We make use of Event and join UserSystemRole and CustomSysRole where we use that user where UserSystemRole.user_id == User.id , CustomSysRole.id == UserSystemRole.role_id, CustomSysRole.name == “Sales Admin” and then we return events in which Event.id == UserSystemRole.event_id
  5. Similarly, for Marketer events we make use of Event and join UserSystemRole and CustomSysRole where we use that user where UserSystemRole.user_id == User.id , CustomSysRole.id == UserSystemRole.role_id, CustomSysRole.name == “Marketer” and then we return events in which Event.id == UserSystemRole.event_id

Schema Updation

For the Marketer and Sales Admin events, we’ll update UserSchema as follows

Now, let’s try to understand this Schema.

In this feature, we are providing user to act as a marketer and sales admin for a event.

  1. For displaying marketer_events relation self_view is displayed by API v1.user_marketer_events and collection of these events is displayed by API v1.event_list
  2. These APIs will return the Events as schema=”EventSchema”. Here, many=True tells us that this is One to many relationship with Events model.

So, we saw how an user can act as a marketer and/or sales admin for many events.

Resources

Continue Reading Adding Marketer and Sales Admin Events Relationship with User on Open Event Server

Adding Custom System Roles in Open Event Server

In this blog, we will talk about how to add different custom system roles concerning a user on Open Event Server. The focus is on its model and Schema updation.

Model Updation

For the User Table, we’ll update our User Model as follows:

Now, let’s try to understand these hybrid properties.

In this feature, we are providing Admin the rights to see whether a user is acting as a Marketer and / or  Sales Admin of any of the event or not. Here, _is__system_role method is used to check whether an user plays a system role like Marketer, Sales Admin or not. This is done by querying the record from UserSystemRole model. If the record is present then the returned value is True otherwise false.

Schema Updation

For the User Model, we’ll update our Schema as follows:

Now, let’s try to understand this Schema.

Since all the properties will return either True or false so these all properties are set to Boolean in Schema.Here dump_only means, we will return this property in the Schema.

So, we saw how User Model and Schema is updated to show custom system roles concerning a user on Open Event Server.

Resources

Continue Reading Adding Custom System Roles in Open Event Server

Adding a Countdown to Orders Page in Open Event Frontend

This blog post will illustrate how you can add a countdown to orders page which on finishing expires the ticket in Open Event. In Open Event we allow some predefined time for users to fill in their details and once the time expires order gets expired and tickets get released. Users can order the tickets again if they want.

We start by adding a createdAt field to orders model so that we can keep track of remaining time. To calculate the time when the order should expire we add predefined time in which user should fill their details to createdAt time. In this way, we get the time when the order will expire.

So now to calculate the remaining time we just subtract the expiring time from current time. And then we render this data into the template. We define getRemainingTime property in our template and fetch the data for that property with help of javascript.

To see the template code visit this link.

The challenge here is to update the time remaining after every second. For this, we take the help of ember runloop. The run.later() function of ember runloop helps us to calculate the property after every second and set it. Code for setting the remaining time with the help of javascript is given below.

// app/components/forms/orders/order-form.js

getRemainingTime: computed('data', function() {
    let willExpireAt = this.get('data.createdAt').add(10, 'minutes');
    this.timer(willExpireAt, this.get('data.identifier'));
  }),

  timer(willExpireAt, orderIdentifier) {
    run.later(() => {
      let currentTime = moment();
      let diff = moment.duration(willExpireAt.diff(currentTime));
      this.set('getRemainingTime', moment.utc(diff.asMilliseconds()).format('mm:ss'));
      if (diff > 0) {
        this.timer(willExpireAt, orderIdentifier);
      } else {
        this.get('data').reload();
        this.get('router').transitionTo('orders.expired', orderIdentifier);
      }
    }, 1000);
  }

 

As given in the code. We pass expiring time and order’s model instance to the timer function. Timer function calculates the remaining time and sets it to getRemainingTime property of template. Timer function runs after every second with the help of run.later() function of ember runloop. To format the remaining time into MM:SS we take help of moment.js library and format the data accordingly.

Once the remaining time is less than zero (time expires) we reload the model and transition current route to expired route. We do not have to set order status as expired inside the FE. Server sets the order as expired after the predefined time. So we just reload the model from the server and we get the updated status of the order.

Resources:
Continue Reading Adding a Countdown to Orders Page in Open Event Frontend

Adding Helper and Adding Action Buttons to Orders List in Open Event Frontend

This blog post will illustrate how to add a helper to orders list and add action buttons to orders list to delete and cancel an order in Open Event Frontend. To cancel or delete an order item we need to communicate to the server. The API endpoints to which we communicate are:

  • PATCH        /v1/orders/{order_identifier}
  • DELETE    /v1/orders/{orders_identifier}

We will define the action buttons in ui-table component of open event frontend. We will use the cell-actions file to define the cell buttons that will be present in cell-actions column. The following handlebars code will render the buttons on website.

//components/ui-table/cell/events/view/tickets/orders/cell-actions.hbs

class="ui vertical compact basic buttons"> {{#if (and (not-eq record.status 'cancelled') (can-modify-order record))}} {{#ui-popup content=(t 'Cancel order') click=(action (confirm (t 'Are you sure you would like to cancel this Order?') (action cancelOrder record))) class='ui icon button' position='left center'}} class="delete icon"> {{/ui-popup}} {{/if}} {{#if (can-modify-order record)}} {{#ui-popup content=(t 'Delete order') click=(action (confirm (t 'Are you sure you would like to delete this Order?') (action deleteOrder record))) class='ui icon button' position='left center'}} class="trash icon"> {{/ui-popup}} {{/if}} {{#ui-popup content=(t 'Resend order confirmation') class='ui icon button' position='left center'}} class="mail outline icon"> {{/ui-popup}}

 

In above code you can see two things. First is can-modify-order which is a helper. Helper is used to simplify conditional logics which cannot be easily placed in handlebars. Second thing is action. There are two actions defined: cancelOrder and deleteOrder. We will see implementation of these later. First let’s see how we define can-modify-order helper.

In can-modify-order helper we want to return true or false in case we want cancel button and delete button to display or not respectively. We write the code of can-modify-order in helpers/can-modify-order.js file. When we want to get result from this helper we call it from handlebars file and pass any parameter that we want to use in helper. Code for can-modify-order helper is given below.

// helpers/can-modify-order.js

import Helper from '@ember/component/helper';

export function canModifyOrder(params) {
 let [order] = params;
 if (order.amount !== null && order.amount > 0) {
   // returns false if order is paid and completed
   return order.status !== 'completed';
 }
 // returns true for free ticket
 return true;
}

export default Helper.helper(canModifyOrder);

 

We extract the parameter and store it in order variable. We see if it satisfies our conditions we return true else false.

Now lets see how we can define actions to perform delete and cancel action on a order. We define these actions in controllers section of app. After performing suitable operation with order we call save to update modified order and destroyRecord() to delete an order. Let see the code implementation for these actions.

actions: {
   deleteOrder(order) {
     this.set('isLoading', true);
     order.destroyRecord()
       .then(() => {
         this.get('model').reload();
         this.notify.success(this.get('l10n').t('Order has been deleted successfully.'));
       })
       .catch(() => {
         this.notify.error(this.get('l10n').t('An unexpected error has occurred.'));
       })
       .finally(() => {
         this.set('isLoading', false);
       });
   },
   cancelOrder(order) {
     this.set('isLoading', true);
     order.set('status', 'cancelled');
     order.save()
       .then(() => {
         this.notify.success(this.get('l10n').t('Order has been cancelled successfully.'));
       })
       .catch(() => {
         this.notify.error(this.get('l10n').t('An unexpected error has occurred.'));
       })
       .finally(() => {
         this.set('isLoading', false);
       });
   }

 
After defining these actions, buttons in the orders list start working. In this way, we can make use of helper to simplify the conditional logic inside templates and define proper actions.

Resources:
Continue Reading Adding Helper and Adding Action Buttons to Orders List in Open Event Frontend