Addition of new filters for event search

Open Event has an event search provided but it lacked two of the userful filters which will make searching for an event for a user easier than the current ecosystem. In this blog post, I describe how I implemented filtering of events on the basis of CFP status and Ticket Type. About the issue Addition of these two filters were subparts of improving the browse events page better. The browse events page currently functions in an optimal way but these improvements make it even better. How the filters are added For adding these two filters, it was required that the request sent to server to filter the event must contain ticket type and cfp so that the results from the server can be received. To achieve this, the frontend code needed the following changes: Passing of request variable into sidebar component present in app/templates/explore.hbs and addition of a clear filter for the same in the same file.e startDate=start_date endDate=end_date location=location ticket_type=ticket_type} {{explore/side-bar model=model category=category sub_category=sub_category event_type=event_type startDate=start_date endDate=end_date location=location ticket_type=ticket_type}}{{#if filters.ticket_type}}  <div class="ui mini label">    {{ticket_type}}    <a role="button" {{action 'clearFilter' 'ticket_type'}}>      <i class="icon close"></i>    </a>  </div>{{/if}} Adding UI for both the filters in app/templates/components/explore/side-bar.hbs. Accordion UI is used to achieve this.   <div class="item">    {{#ui-accordion}}      <span class="title">        <i class="dropdown icon"></i>        {{t 'Ticket Type' }}      </span>      <div class="content menu">        <a href="#"          class="link item {{if (eq ticket_type 'free') 'active'}}"          {{action 'selectTicketType' 'free'}}>          {{t 'Free'}}        </a>        <a href="#"          class="link item {{if (eq ticket_type 'paid') 'active'}}"          {{action 'selectTicketType' 'paid'}}>          {{t 'Paid'}}        </a>      </div>    {{/ui-accordion}}  </div> Editing the routes (app/routes/explore.js) to make sure if the request has new filter parameter then it should be sent to server. if (params.ticket_type) {      filterOptions.push({        name : 'tickets',        op   : 'any',        val  : {          name : 'type',          op   : 'eq',          val  : params.ticket_type        }      });    } Addition of new request parameter in the controller (app/controllers/explore.js) queryParams  : ['category', 'sub_category', 'event_type', 'start_date', 'end_date', 'location', 'ticket_type'],ticket_type  : null,if (filterType === 'ticket_type') {  this.set('ticket_type', null);} Editing the sidebar component to set the value of request parameter when the user interacts with the filter. hideClearFilters: computed('category', 'sub_category', 'event_type', 'startDate', 'endDate', 'location', 'ticket_type', function() {    return !(this.category || this.sub_category || this.event_type || this.startDate || this.endDate || this.location || this.ticket_type !== null);}),selectTicketType(ticketType) {  this.set('ticket_type', ticketType === this.ticket_type ? null : ticketType);},this.set('ticket_type', null); Sidebar after the addition of filters. Resources: Issue: https://github.com/fossasia/open-event-frontend/issues/3098Pull Requests: Ticket Type: https://github.com/fossasia/open-event-frontend/pull/3158CFS: https://github.com/fossasia/open-event-frontend/pull/3144 Specifying Query Params: https://guides.emberjs.com/release/routing/query-params/ UI Resources for the feature: https://semantic-org.github.io/Semantic-UI-Ember/#/modules/accordion

Continue ReadingAddition of new filters for event search

Allow Same Discount/Access Code for Multiple Events in the Open Event Server

In this Blog-Post, I will show how to allow the system to create the same Discount/Access Code for multiple events in the Open Event Server. What was the issue: The main problem was that the server used to identify the discount code and access code based on the discount code/access code itself, which did not allow multiple events to have the same discount/access codes. Can you think of a better solution to this?Yes, we should have been searching for it based on the discount/access code as well as the event they are associated with. Changing the endpoint: Now to do so, we want to pass the id of the event as well as discount/access code itself with the endpoint so that we can search the database based on the event_id and the code itself.   Changes in Discount/Access Code Endpoint: '/event/<int:discount_event_id>/discount-code/<code>''/event/<int:access_event_id>/access-code/<code>' Change logic for database search: Now when searching for discount/access code in the database, we need to pass the event_id along with the discount/access code, so that we can get the column of discount/access code associated with that event, even if we have multiple discount/access code with the same name for a different event.  Changes in Database search logic: access = db.session.query(AccessCode).filter_by(code=kwargs.get('code')event_id = kwargs.get('access_event_id')).first() discount = db.session.query(DiscountCode).filter_by(code=kwargs.get('code'),event_id = kwargs.get('discount_event_id')).first() Change endpoint in API docs and update Dredd hooks: Now that we have changed the endpoint to get a discount/access code, we need to change API docs as well as Dredd hooks to accommodate the change in API docs. Changes in API docs: ## Get Discount Code Detail using the code [/v1/event/{event_id}/discount-code/{code}] ## Get Access Code Detail using the code [/v1/event/{event_id}/access-code/{code}] Changes in Dredd Hooks: In discount code hook: discount_code.event_id = 1 In access code hook: event = EventFactoryBasic()db.session.add(event)db.session.commit() Resources: Link to Issue: fossasia/open-event-server#6027Link to PR: fossasia/open-event-server#6208

Continue ReadingAllow Same Discount/Access Code for Multiple Events in the Open Event Server

Implementing Barcode Scanning in Open Event Android Orga App using RxJava

One of the principal goals of Open Event Orga App (Github Repo) is to let the event organizer to scan the barcode identifier of an attendee at the time of entry in the event, in order to quickly check in that attendee. Although there are several scanning APIs available throughout the web for Android Projects, we chose Google Vision API as it handles multitude of formats and orientations automatically with little to no configuration, integrates seamlessly with Android, and is provided by Google itself, ensuring great support in future as well. Currently, the use case of our application is: Scan barcode from the camera feed Detect and show barcode information on screen Iterate through the attendee list to match the detected code with unique attendee identifier Successfully return to the caller with scanned attendee’s information so that a particular action can be taken There are several layers of optimisations done in the Orga Application to make the user interaction fluid and concise. I’ll be sharing a few in this blog post regarding the configuration and handling of bursty data from camera source efficiently. To see the full implementation, you can visit the Github Repository of the project using the link provided above. Configuration The configuration of our project was done through Dagger 2 following the dependency injection pattern, which is not the focus of this post, but it is always recommended that you follow separation of concerns in your project and create a separate module for handling independent works like barcode scanner configuration. Normally, people would create factories with scanner, camera source and processors encapsulated. This enables the caller to have control over when things are initialized. Our configuration provides us two initialised objects, namely, CameraSource and BarcodeDetector @Provides BarcodeDetector providesBarCodeDetector(Context context, Detector.Processor<Barcode> processor) { BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context) .setBarcodeFormats(Barcode.QR_CODE) .build(); barcodeDetector.setProcessor(processor); return barcodeDetector; } @Provides CameraSource providesCameraSource(Context context, BarcodeDetector barcodeDetector) { return new CameraSource .Builder(context, barcodeDetector) .setRequestedPreviewSize(640, 480) .setRequestedFps(15.0f) .setAutoFocusEnabled(true) .build(); } The fields needed to create the objects are provided as arguments to the provider functions as all the dependencies required to construct these objects. Now focusing on the Detector.Processor requirement of the BarcodeDetector is the classic example on non injectable code. This is because the processor is to be supplied by the activity or any other object which wants to receive the callback with the detected barcode data. This means we could inject it at the time of creation of the Activity or Presenter itself. We could easily overcome by adding a constructor to this dagger module containing the Barcode.Processor at the time of injection, but that would violate our existing 0 configuration based model where we just get the required component from the Application class and inject it. So, we wrapped the the processor into a PublishSubject @Provides @Singleton @Named("barcodeEmitter") PublishSubject<Notification<Barcode>> providesBarcodeEmitter() { return PublishSubject.create(); } @Provides @Singleton Detector.Processor<Barcode> providesProcessor(@Named("barcodeEmitter") PublishSubject<Notification<Barcode>> emitter) { return new Detector.Processor<Barcode>() { @Override public void release() { // No action to be taken } @Override public void receiveDetections(Detector.Detections<Barcode> detections) {…

Continue ReadingImplementing Barcode Scanning in Open Event Android Orga App using RxJava

Building Android preference screen

Some days ago, I started building a Setting Screen for my Android app. Everything was fine, until I opened it on an older Android version. The overview screen had no material design, a thing I would have accepted, if there weren’t those completely destroyed dialogs: Android’s internal preferences are using Android’s internal app.AlertDialogs. Those dialogs in combination with the AppCompat Dialog Theme, which I had applied to them, resulted in a dialog with two frames on older devices (One system default dialog and a material frame around it). So I decided to switch to the android.support.v7.preference library, only to face a lot more issues. Including the Library In order to use the new preferences, we need to import a library. To do so, we add this line to our gradle dependencies (You should change the version number to the latest). compile 'com.android.support:preference-v7:23.4.0' Building The Preference Screen Creating the Preferences At first, we need to create our preference structure: We create a new XML Android resource file as xml/app_preferences.xml. Now we can add our preference structure to this file. Make sure to add a unique android:keyattribute for each preference. More information: How to build the XML <android.support.v7.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <android.support.v7.preference.PreferenceCategory android:title="Category 1"> <android.support.v7.preference.SwitchPreferenceCompat android:key="key1" android:title="Switch Preference" android:summary="Switch Summary" android:defaultValue="true" /> <android.support.v7.preference.EditTextPreference android:key="key2" android:title="EditText Preference" android:summary="EditText Summary" android:dialogMessage="Dialog Message" android:defaultValue="Default value" /> <android.support.v7.preference.CheckBoxPreference android:key="key3" android:title="CheckBox Preference" android:summary="CheckBox Summary" android:defaultValue="true"/></android.support.v7.preference.PreferenceCategory></android.support.v7.preference.PreferenceScreen> The v7.preference library provides some preferences we can use: CheckBoxPreference, SwitchPreferenceCompat, EditTextPreference and a ListPreference (and a basic Preference). If we need more than these predefined preferences, we have to build them on our own. Creating the Preference Fragment Now we need to create our Preference Fragment, where we can show the preferences from our XML file. We do this by creating a new class, called SettingsFragment, which extends PreferenceFragmentCompat. Since the onCreatePreferences is declared as abstract in the source code of the library, we are forced to include our own implementation to tell the fragment to load our just created app_preferences.xml. import android.support.v7.preference.PreferenceFragmentCompat; public class SettingsFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle bundle, String s) { // Load the Preferences from the XML file addPreferencesFromResource(R.xml.app_preferences); } } We can add this SettingsFragment (v4.app.Fragment), like any other Fragment (e.g. with a FragmentTransaction) to an Activity. Applying the Preference Theme Finally we need to specify a preferenceTheme in our Activity’s theme. If we don’t do so, the App will crash with an IllegalStateException. The v7.preference library provides only one Theme: PreferenceThemeOverlay(You may have a look at its source code). We add this with the following line in our Activity’s theme: <item name="preferenceTheme">@style/PreferenceThemeOverlay</item> After we have done this, our result should now look like this. (The Activity’s parent theme is Theme.AppCompat and the background is set with android:windowBackground) Settings Screen with PreferenceThemeOverlay As you can see, it has an oversized font and a horizontal line below the category title. This is definitely not material design. It more looks like a mixture of material design for the CheckBoxand Switch widgets on the right and an old…

Continue ReadingBuilding Android preference screen

Using ftp-deploy in node.js to publish websites over FTP

In the Open Event Webapp Generator, we recently added the functionality for organisers to submit their ftp credentials and when the website is generated, it'll automatically upload the website to the chosen ftp server (allowing creation of subdirectory internally, if the organiser so wants). To achieve we used the very useful nodejs module ftp-deploy which is a wrapper on the popular jsftp library The code dealing with ftp deployment in our webapp generator can be found here  - https://github.com/fossasia/open-event-webapp/blob/development/src/backend/ftpdeploy.js As can be seen, deploying using ftp-deploy is pretty straightforward. Primarily we need a config object   var config = { username: ftpDetails.user, //prompted on commandline if not given password: ftpDetails.pass, // optional, prompted if none given host: ftpDetails.host, port: 21, localRoot: path.join(__dirname, '/../../dist', appFolder), //local folder containing website remoteRoot: ftpDetails.path, //path on ftp server to host website exclude: ['.git', '.idea', 'tmp/*'], continueOnError: true }; You can set up some event listeners for events like uploaded uploading and upload-error

Continue ReadingUsing ftp-deploy in node.js to publish websites over FTP