Badgeyay comes with many features for customising the process of generation of Badges. It gives freedom to user to choose Input Badge data which is to be printed on the individual badges, choosing the badge size, applying custom background to the badges and then optional features of font customization helps to generate cool badges. If a helper is not there for the directions to use these features then these features may be difficult to use for a user.
To resolve this issue and make Badgeyay more user friendly I have implemented a User Guide to help user to go through the User Manual before generating Badges in my Pull Request.
To implement user guide, I have used Semantic UI tables to give examples for CSV format and used other components for Manual format.
Let’s get started and understand it step by step.
Create User Guide component with Ember CLI.
Now, We will use Semantic UI while editing Handlebars.
class="user-guide">
class="ui center aligned huge header">User-Input Guide
class="ui center aligned small header">
Please check what is the "Correct Format"?
class="ui segments">
class="ui segment">
class="ui raised segment">
class="ui header">
class="file excel icon">
class="content">
CSV Format
</div>
</div>
class="ui bulleted list">
class="item">The CSV must be uploaded with 5 columns of data.
class="item">Five comma (',') seperated values should be present in the CSV
class="item">See Example Below
<table class="ui celled structured table">
<thead>
<tr>
<th rowspan="2">First Name
</th>
<th rowspan="2">Last Name
</th>
<th rowspan="2">Position
</th>
<th rowspan="2">Organisation/Project
</th>
<th rowspan="2">Social Handle
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Deepjyoti
</td>
<td>Mondal
</td>
<td>Mentor
</td>
<td>FOSSASIA
</td>
<td>@djmgit
</td>
</tr>
<tr>
<td>Yash
</td>
<td>Ladha
</td>
<td>Developer
</td>
<td>Badgeyay
</td>
<td>@yashladha
</td>
</tr>
<tr>
<td>Manish
</td>
<td>Devgan
</td>
<td>Developer
</td>
<td>Badgeyay
</td>
<td>@gabru-md
</td>
</tr>
<tr>
<td>Parth
</td>
<td>Shandilya
</td>
<td>Developer
</td>
<td>Badgeyay
</td>
<td>@ParthS007
</td>
</tr>
</tbody>
</table>
</div>
</div>
class="ui segment">
class="ui raised segment">
class="ui header">
class="edit icon">
class="content">
Manual Data Format
</div>
</div>
class="ui bulleted list">
class="item">Format for Manual data is same as CSV's data
class="item">Five comma (',') seperated values on each line is the correct format
class="item">See Example below
class="ui segment">
Deepjyoti,Mondal,Mentor,FOSSASIA,@djmgit
Yash,Ladha,Developer,FOSSASIA,@yashladha
Manish,Devgan,Developer,FOSSASIA,@gabru-md
Parth,Shandilya,Developer,FOSSASIA,@ParthS007
</div>
</div>
</div>
</div>
Step 3:
Link it with Create Badges as a tooltip in the first accordian of create badges route.
<a class="ui icon orange button guide" href="{{href-to 'user-guide'}}" data-tooltip="User Input Guide" data-position="right center"><i class="info icon"></i></a>
I have implemented the user guide for the user to go through the User Manual before generating Badges.
Step 4::
Now run the server to see the implemented changes by following command.
User Guide Component
Tooltip present in the create badges form.
Now, we are done implementing a User Guide to help user to go through the User Manual before generating Badges.
Resources:
- Ember Docs – Link
- Badgeyay Repository – Link
- Issue Link – Link
- Semantic UI – LInk
This blog will illustrate about how we, at Open Event Android, have implemented the way to show the number of tickets of every type of ticket bought by the user in Orders Under User fragment itself!
1. Modify ordersUnderUser function in Order API
The ordersUnderUser function in Order API doesn’t include attendees. So, if we we need to show the number of attendees which is basically the number of tickets, we have to include all the attendee ids.
@GET(“/v1/users/{userId}/orders?filter=[{\”name\”:\”status\”,\”op\”:\”eq\”,\”val\”:\”completed\”}]&include=event,attendees&fields[attendees]=id”)
fun ordersUnderUser(@Path(“userId”) userId: Long): Single<List<Order>>
|
1. Modify the orderUnderUser function in viewmodel
Now, we have to modify the OrderViewModel where we will make changes in the orderUnderUser function. We create a LiveData of attendees number which will contain a list of attendee ids received from the order.
val attendeesNumber = MutableLiveData<ArrayList<Int>>()
|
Then, in the orderUnderUser function, we add a line of code of setting the value of the LiveData.
This basically takes the orders as a list and as List<AttendeeId> is a variable inside the object of Order, we map out the same ArrayList full of attendee ids!
…
}.subscribe({
order = it
attendeesNumber.value = it.map { it.attendees?.size } as ArrayList<Int>
val query = buildQuery(it)
if (idList.size != 0)
eventsUnderUser(query)
else
progress.value = false
}
|
2. Modify OrdersUnderUserFragment code
We add a observer in the Fragment file. The observer will fire up whenever there is a value received for attendeesNumber. It will fire up the function setAttendeeNumber in ordersRecyclerAdapter.
ordersUnderUserVM.attendeesNumber.observe(this, Observer {
it?.let {
ordersRecyclerAdapter.setAttendeeNumber(it)
}
})
|
3. Modify OrdersRecyclerAdapter code
We add a variable called attendeesNumber in the file. Another function called setAttendeeNumber is also made to set the Attendee number. We then proceed to bind the number to the view holder.
var attendeesNumber = ArrayList<Int>()
fun setAttendeeNumber(number: ArrayList<Int>) {
attendeesNumber = number
}
override fun onBindViewHolder(holder: OrdersViewHolder, position: Int) {
holder.bind(eventAndOrderIdentifier[position].first, clickListener, eventAndOrderIdentifier[position].second, attendeesNumber[position])
}
|
4. Modify the ViewHolder of an Order
We create a conditional which thus sets up the message of “See N Tickets” or “See 1 Ticket” based on the ticket number.
if (attendeesNumber == 1) {
itemView.ticketsNumber.text = “See ${attendeesNumber} Ticket”
} else {
itemView.ticketsNumber.text = “See ${attendeesNumber} Tickets”
}
|
Thus, this was how, tickets number viewing was implemented in the app.
References
Tags: GSoC18, FOSSASIA, Open Event, Android, Number of Tickets
This blog will illustrate about how forgot password feature is implemented in the Open Event Android app. This feature is quite necessary for users as the user might forget his or her password whenever he needs to login. Thus, this feature utilises only the email of the user. When clicked on “I forgot my password” option, the user is sent an email to reset his/her password!
1. Create the RequestToken, Email and RequestToken response models
The first step is to create all required models. We actually send a POST request to the server and the body of it contains the RequestToken model. The response received is contained in the RequestToken response model. We create an Email model for our use.
RequestToken class:-
data class RequestToken(val data: Email)
|
Email class:-
data class Email(val email: String)
|
RequestTokenResponse class:-
data class RequestTokenResponse(val message: String)
|
2. Show the option only when correct Email Id is entered.
We create a verification method to verify the email. The app will only send a POST request using a correct email. This method is present in the ViewModel.
fun showForgotPassword(email: String): Boolean {
if (email.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
return true
}
return false
}
|
2. Update the Login Fragment file.
We add an onclicklistener to the forgot password option. This will call a function in the ViewModel. The function is sendResetPasswordEmail which utilises the actual email of the user entered.
rootView.forgotPassword.setOnClickListener {
loginActivityViewModel.sendResetPasswordEmail(email.text.toString())
}
|
3. Update the ViewModel code
We create the sendResetPasswordEmail method. Below code represents that.
fun sendResetPasswordEmail(email: String) {
compositeDisposable.add(authService.sendResetPasswordEmail(email)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {
progress.value = true
}.doFinally {
progress.value = false
}.subscribe({
requestTokenSuccess.value = verifyMessage(it.message)
}, {
error.value = “Email address not present in server. Please check your email”
}))
}
|
3. Create an observer for the requestTokenSuccess variable in the Fragment.
Thus, the final task at hand is to create an observer to observe the vaue of requestTokenSuccess variable. Once the variable is set to a message “Email Sent”, we can clearly notify the user that the email is sent perfectly! (The feature image represents this)
Thus, this is how we have implemented the forgot password feature in the app.
References
Tags: GSoC18, FOSSASIA, Open Event, Android, Forgot Password
The Open Event Android app uses innumerable open source softwares. Fortunately, android allows us to give credit to each OSS (Open Source Software). We can do this just by writing a few lines of code. In this blog we will illustrate about how we are showing a list of acknowle- dgements in the Open Event Android app.
First of all we will add all the dependencies required. In the app level gradle file, we will add the plugin.
apply plugin: ‘com.google.gms.oss.licenses.plugin’ |
We then add the implementation of oss licences in the app level file of build.gradle
implementation ‘com.google.android.gms:play-services-oss-licenses:16.0.0’ |
After that we add the classpath to the project level gradle file in dependencies.
classpath “com.google.gms:oss-licenses:0.9.2” |
The google() function must be added in maven for this to work. So, after adding all these dependencies, we click the Sync button in Android Studio. We wait for the project to refresh.
In our Settings Fragment file, we add another preference called “Acknowledgements”. Let us head into the code below. In the SettingsFragment file.
if (preference?.key == resources.getString(R.string.key_acknowledgements)) {
startActivity(Intent(context, OssLicensesMenuActivity::class.java))
return true
} |
As we can see, we have added a conditional in the onPreferenceClickListener. If the user clicks on a preference whose key is “key_acknowledgements”, an OssLicensesMenyActivity opens in the app. This is a predefined activity and is only available after we have successfully integrated oss licences. Heading onto some xml code for the feature. We move onto settings.xml file.
<Preference
android:key=”@string/key_acknowledgements”
android:title=”@string/acknowledgements_settings” /> |
This section is present under the main PreferenceScreen. It is nested and is actually present under a PreferenceCategory named “About”. The final thing we do to complete the process successfully is store our strings in the strings.xml file.
<string name=”key_acknowledgements”>key_acknowledgements</string>
<string name=”acknowledgements_settings”>Acknowledgements</string> |
Thus, this is how we are able to show the user a list of acknowledgements successfully in the Open Event android app.
Additional Resources
Tags: GSoC18, FOSSASIA, Open Event, Android, OSS
The Open Event Web App has two components :
- An event website generator
- The actual generated website output.
The web generator application can generate event websites by getting data from event JSON files and binary media files, that are stored in a compressed zip file or through an API endpoint. The JSON data format of version 1 as well as version 2, provides user an option to add the slide and video URLs of the sessions. The data from JSONs is extracted and stored in the objects for a particular session, and in the template, the data for videos and slides are rendered in their corresponding iframes.
Extracting data from event JSONs
The data is extracted from the JSONs and is stored in an object. The object containing the data is sent to the procedure which compiles the handlebars templates with that data.
JSON data format v1
video: session.video,
slides: session.slides,
audio: session.audio
JSON data format v2
video: session['video-url'],
slides: session['slides-url'],
Audio: session['audio-url']
The JSON data format for v1 and v2 are different and thus the data is extracted from the file depending on API version chosen for web app generation. The files where data extraction takes place are fold_v1.js and fold_v2.js for API v1 and v2 respectively.
Adding event emitter
Onclick event emitter on schedule division calls the procedure “loadVideoAndSlides” with the parameters corresponding to the session clicked.
<div class="schedule-track" id="{{session_id}}" onclick = "loadVideoAndSlides('{{session_id}}', '{{video}}', '{{slides}}')">
.....
.....
</div>
The parameters Session ID, Video URL and Slide URL are passed to the procedure which is responsible for displaying the slides and video iframes for the sessions. This resolves the problem of heavy data binding to the page, as the frames for videos and slides are loaded on page only when the session is clicked.
Procedure called on click event
The performance of web app is significantly improved by using the call and listen mechanism as only the requested videos are loaded into the document object model.
function loadVideoAndSlides(div, videoURL, slideURL){
if(videoURL !== null && videoURL !== '') {
$('#desc-' + div).children('div').prepend(' + div + '" class = "video-iframe col-xs-12 col-sm-12 col-md-12" src="https://www.youtube.com/embed/' + videoURL + '" frameborder="0" allowfullscreen>');
}
if(slideURL !== null && slideURL !== '') {
$('#desc-' + div).children('div').prepend(' + div + '" class = "iframe col-xs-12 col-sm-12 col-md-12" frameborder="0" src="https://view.officeapps.live.com/op/embed.aspx?src=' + slideURL +'">');
}
}
The video and slide URLs passed to the procedure are used for loading the iframes from youtube and office apps or google docs respectively as shown above, and the resulting slide view is as shown below
Resources
Open Event Web app generator provides an option to event organizers to choose the theme for their event website. Previously it supported the default light theme for the websites, but now it supports a customized dark-theme as well inspired from the twitter dark-mode. Adding this new feature to the User Interface of the generated website, Open Event Web app provides a stylish view for the website of an event.
How we enabled multiple theme support?
The client is provided an option to choose the theme, either ‘light’ or ‘dark’ from the generator. Depending on the option selected, the data is sent to the server, the server extracts the data and while compiling the stylesheet for the pages takes into the account which theme is chosen by the client.
Adding option to choose theme
A drop-down menu is added on the generator page which lets the client choose either of the light or dark themes. The default theme is light.
<label for="theme">Choose your theme</label>
<select class="form-control" id="theme" name="theme">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
Defining the color schema
The color schema is set different for both the themes, this is achieved by making two different stylesheets for the light and dark themes. The style or color of an element is assigned a variable in main css file(application.scss). Those variables are overwritten while compiling these specific files depending upon the theme chosen.
_light.scss
Defines the values of variables for light theme.
$navbar-color: #ffffff;
$link-color: $gray-dark !default;
$hover-color: $black !default;
$span-background: #efefef !default;
_dark.scss
Defines the values of variables for dark theme.
$navbar-color: #2b324a;
$link-color: $light-blue;
$hover-color: $light-blue;
$span-background: #333d5a;
Setting up theme field in json data
The json data to be used for compiling the templates, sets or unsets the theme field according to the theme selected by the client.
if (req.body.theme === 'light') {
jsonData.theme = 0;
} else {
jsonData.theme = 1;
}
Rendering style in template files
Now we have the value for theme selected by the client, the data used for rendering the CSS file is chosen accordingly. If the theme is light, the file containing color-scheme for light proposition is selected else the dark one. The output file contains the values for color variables according to the theme.
sass.render({
file: __dirname + '/_scss/_themes/_' + theme + '-theme/_' + theme + '.scss',
outFile: distHelper.distPath + '/' + appFolder + '/css/schedule.css'
}, function(err, result) {
if (!err) {
...
... // Minifying CSS file and writing
callback(null);
});
The output file is schedule.css which contains the style for different pages according to the theme chosen while web app generation.
Resources
As any user can add or remove devices from their account, there needed to be a way by which Admins can manage the user devices. The Admins and higher user roles should have the access to modify the config of devices of any user. This blog post explains how an API has been implemented to facilitate Admins and higher user roles to change config of devices of any user.
Implementing a servlet to allow changing review status of a Skill
The basic task of the servlet is to allow Admin and higher user roles to modify the config of devices of any user. The Admin should be allowed to edit the name of the device and also the room of the device, similar to how a user can edit his own devices.
Here is the implementation of the API:
- The API should be usable to only the users who have a user role Admin or higher. Only those with minimum Admin rights should be allowed to control what Skills are displayed on the CMS site. This is implemented as follows:
@Override
public UserRole getMinimalUserRole() {
return UserRole.ADMIN;
}
- The endpoint for the API is ‘/cms/modifyUserDevices.json’. This is implemented as follows:
@Override
public String getAPIPath() {
return "/cms/modifyUserDevices.json";
}
- The main method of the servlet is the serviceImpl() method. This is where the actual code goes which will be executed each time the API is called. This is implemented as follows:
JSONObject result = new JSONObject(true);
Collection<ClientIdentity> authorized = DAO.getAuthorizedClients();
List<String> keysList = new ArrayList<String>();
authorized.forEach(client -> keysList.add(client.toString()));
String[] keysArray = keysList.toArray(new
String[keysList.size()]);
List<JSONObject> userList = new ArrayList<JSONObject>();
for (Client client : authorized) {
JSONObject json = client.toJSON();
if(json.get("name").equals(email)) {
ClientIdentity identity = new ClientIdentity(ClientIdentity.Type.email, client.getName());
Authorization authorization = DAO.getAuthorization(identity);
ClientCredential clientCredential = new ClientCredential(ClientCredential.Type.passwd_login, identity.getName());
Authentication authentication = DAO.getAuthentication(clientCredential);
Accounting accounting = DAO.getAccounting(authorization.getIdentity());
if(accounting.getJSON().has("devices")) {
JSONObject userDevice = accounting.getJSON().getJSONObject("devices");
if(userDevice.has(macid)) {
JSONObject deviceInfo = userDevice.getJSONObject(macid);
deviceInfo.put("name", name);
deviceInfo.put("room", room);
}
else {
throw new APIException(400, "Specified device does not exist.");
}
} else {
json.put("devices", "");
}
accounting.commit();
}
}
Firstly, the list of authorized clients is fetched using DAO.getAuthorizedClients() and is put in an ArrayList. Then we traverse through each element of this ArrayList and check if the device exists by checking if there’s a key-value pair corresponding to the macid passed in the query parameter. If the device doesn’t exist, then an exception is thrown. However, if the macid exists in the traversed element of the ArrayList, then we put the name and the room of the device as passed as query parameters in that particular element of the ArrayList, so as to overwrite the existing name and room of the device of the user.
This is how an API has been implemented which allows Admins and higher user roles to modify the config of devices of any user.
Resources
You must be logged in to post a comment.