Badge Generation : Adding Progress Bar

A Badge generator like Badgeyay must be able to generate, store and export the user data as and when needed. This blog post covers the addition of ember-progress-bar in the badgeyay project. This progress bar shows real-time progress of the badge generation process. Adding the functionality to badgeyay Let us see how we implemented this functionality into the backend of the project. Step 1 : Adding the package to package.json Image link is the link to the user’s uploaded image on remote firebase server. ember install ember-progress-bar or npm install ember-progress-bar --save Step 2 : Adding the progressbar to the frontend Once we have installed the progress bar, we need to display it onto the frontend of the project. To do that we use the handlebars templating engine to render the progress bar. {{#if showProgress}} <div class="ui segment"> <div class="ui centered aligned grid">{{progressState}}</div> <div class="ui divider"></div> {{ember-progress-bar progress=progress options=(hash color='orange')}} </div> {{/if}} Step 3 : Now we need to define states We need to define the states that the progress bar will take up in realtime. And to do so, we make changes to the create-badges controller showProgress   : false, progress       : 0, progressState  : '', Now we manage the states according to the functionality that has been done. this.set('showProgress', true); this.set('progress', 0.1); this.set('progressState', 'Setting Paper Size'); ... this.set('progress', 0.4); this.set('progressState', 'Gathering background'); ... this.set('progress', 0.7); this.set('progressState', 'Preparing your badges'); ... this.set('showProgress', false); this.set('progress', 0); this.set('progressState', ''); ... Finally, we have our basic progress bar ready for the users to view. Screenshot of changes Resources The Pull Request for the same : https://github.com/fossasia/badgeyay/pull/1284 The Issue for the same : https://github.com/fossasia/badgeyay/issues/1283 Read about Ember data : https://www.emberjs.com/api/data/classes/DS.Model.html Read about Handlebars :   https://guides.emberjs.com/release/templates/handlebars-basics/

Continue ReadingBadge Generation : Adding Progress Bar

Modifying the My-Badges Component

A Badge generator like Badgeyay must be able to generate, store and export the user data as and when needed. This blog post is about modify the my-badges component to show the badges in a more creative manner.. For making the badges look better than they already are, we decided to use another type of semantic-ui card. This card requires an image. So we decided to use the user’s uploaded image as the image for the badge card. For this, we made changes to the backend along with the frontend. Adding the functionality to badgeyay Let us see how we implemented this functionality into the backend of the project. Step 1 : Adding the image_link to backend Image link is the link to the user’s uploaded image on remote firebase server. image_link = db.Column(db.String) # adding column to table image_link = fields.Str(required=True)  # adding to schema link = fileUploader(imageDirectory, 'images/' + image_name) badge_created.image_link = link  # uploading the file and storing the link Step 2 : Adding a details to frontend model Now we need add the attributes to the frontend model to accept our image_link data.. import DS from 'ember-data'; const { Model, attr } = DS; export default Model.extend({ badge_size    : attr('string'), csv           : attr('string'), download_link : attr('string'), image         : attr('string'), text_color    : attr('string'), image_link    : attr('string') }); Step 3 : Adding required Handlebar code and SCSS Now we need to add the handlebar code to render the image from the link provided from the ember data model. <div class="image"> <img src="{{badge.image_link}}"> </div> And apply some CSS to the image and card .ui.segment { .cards { .card { padding-right: 10px; img { height: 300px; width: 100%; } } } } Finally, we need to apply the migrations to the backend server as well. This is carried out by flask-migrate easily. Screenshot of changes Resources The Pull Request for the same : https://github.com/fossasia/badgeyay/pull/1226 The Issue for the same : https://github.com/fossasia/badgeyay/issues/1221 Read about Ember data : https://www.emberjs.com/api/data/classes/DS.Model.html Read about Handlebars :   https://guides.emberjs.com/release/templates/handlebars-basics/  

Continue ReadingModifying the My-Badges Component

Exporting CSV data through API

A Badge generator like Badgeyay must be able to generate, store and export the user data as and when needed. This blog post is about adding the exporting functionality to badgeyay backend.. Why do we need such an API? Exporting data is required for a user. A user may want to know the details he/she has uploaded to the system or server. In our case we are dealing with the fact of exporting the CSV data from backend of Badgeyay. Adding the functionality to backend Let us see how we implemented this functionality into the backend of the project. Step 1 : Adding the necessary imports We first need to import the required dependencies for the route to work import os import base64 import uuid from flask import request, Blueprint, jsonify from flask import current_app as app from api.models.file import File from api.schemas.file import ExportFileSchema from api.utils.errors import ErrorResponse from api.schemas.errors import FileNotFound Step 2 : Adding a route This step involves adding a separate route that provides us with the exported data from backend. @router.route('/csv/data', methods=['GET']) def export_data(): input_data = request.args file = File().query.filter_by(filename=input_data.get('filename')).first() if file is None: return ErrorResponse(FileNotFound(input_data.get('filename')).message, 422, {'Content-Type': 'application/json'}).respond() export_obj = { 'filename': file.filename, 'filetype': file.filetype, 'id': str(uuid.uuid4()), 'file_data': None} with open(os.path.join(app.config.get('BASE_DIR'), 'static', 'uploads', 'csv', export_obj['filename']), "r") as f: export_obj['file_data'] = f.read() export_obj['file_data'] = base64.b64encode(export_obj['file_data'].encode()) return jsonify(ExportFileSchema().dump(export_obj).data) Step 2 : Adding a relevant Schema After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user. class ExportFileSchema(Schema): class Meta: type_ = 'export-data' kwargs = {'id': '<id>'} id = fields.Str(required=True, dump_only=True) filename = fields.Str(required=True, dump_only=True) filetype = fields.Str(required=True, dump_only=True) file_data = fields.Str(required=True, dump_only=True) This is the ExportFileSchema that produces the output results of the GET request on the route. This helps us get the data onto the frontend. Further Improvements We are working on making badgeyay more comprehensive yet simple. This API endpoint needs to get registered onto the frontend. This can be a further improvement to the project and can be iterated over the next days. Resources The Pull Request for the same : https://github.com/fossasia/badgeyay/pull/1138 The Issue for the same : https://github.com/fossasia/badgeyay/issues/1137 Read about adding routes Blueprint : http://flask.pocoo.org/docs/1.0/blueprints/ Read about Schemas : https://github.com/marshmallow-code/marshmallow-jsonapi

Continue ReadingExporting CSV data through API

Dated queries in Badgeyay admin

Badgeyay is not just an anonymous badge generator that creates badges according to your needs, but it now has an admin section that allows the admin of the website to control and look over the statistics of the website. Why do we need such an API? For an admin, one of the most common functionality is to gather the details of the users or the files being served onto or over the server. Not just that, but the admin must also be aware about the traffic or files on the server in a particular duration of time. So we need an API that can coordinate all the stuff that requires dated queries from the backend database. Adding the functionality to backend Let us see how we implemented this functionality into the backend of the project. Step 1 : Adding a route This step involves adding a separate route that provides us with the output of the dated badges queries from backend. @router.route('/get_badges_dated', methods=['POST']) def get_badges_dated(): schema = DatedBadgeSchema() input_data = request.get_json() data, err = schema.load(input_data) if err: return jsonify(err) dated_badges = Badges.query.filter(Badges.created_at <= data.get('end_date')).filter(Badges.created_at >= data.get('start_date')) return jsonify(AllBadges(many=True).dump(dated_badges).data) This route allows us to get badges produced by any user during a certain duration as a JSON API data object. This object is fed to the frontend to render the badges as cards. Step 2 : Adding a relevant Schema After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user. class DatedBadgeSchema(Schema): class Meta: type_ = 'dated-badges' kwargs = {'id': '<id>'} id = fields.Str(required=True, dump_only=True) start_date = fields.Date(required=True) end_date = fields.Date(required=True) class AllBadges(Schema): class Meta: type_ = 'all-badges' self_view = 'admin.get_all_badges' kwargs = {'id': '<id>'} id = fields.Str(required=True, dump_only=True) image = fields.Str(required=True) csv = fields.Str(required=True) badge_id = fields.Str(required=True) text_color = fields.Str(required=True) badge_size = fields.Str(required=True) created_at = fields.Date(required=True) user_id = fields.Relationship( self_url='/api/upload/get_file', self_url_kwargs={'file_id': '<id>'}, related_url='/user/register', related_url_kwargs={'id': '<id>'}, include_resource_linkage=True, type_='User' ) This is the DatedBadge schema that produces the output results of the POST request on the route. And there is the AllBadges schema that produces the output results of the POST request on the route. Further Improvements We are working on adding multiple routes and adding modifications to database models and schemas so that the functionality of Badgeyay can be extended to a large extent. This will help us in making this badge generator even better. Resources The Pull Request for the same : https://github.com/fossasia/badgeyay/pull/1040 The Issue for the same : https://github.com/fossasia/badgeyay/issues/1039 Read about adding routes Blueprint : http://flask.pocoo.org/docs/1.0/blueprints/ Read about Schemas : https://github.com/marshmallow-code/marshmallow-jsonapi  

Continue ReadingDated queries in Badgeyay admin

Get My Badges from Badgeyay API

Badgeyay is no longer a simple badge generator. It has more cool features than before. Badgeyay now supports a feature that shows your badges. It is called ‘my-badges’ component. To get this component work, we need to design a backend API to deliver the badges produced by a particular user. Why do we need such an API? The main aim of Badgeyay has changed from being a standard and simple badge generator to a complete suite that solves your badge generation and management problem. So to tackle the problem of managing the produced badges per user, we need to define a separate route and schema that delivers the generated badges. Adding the functionality to backend Let us see how we implemented this functionality into the backend of the project. Step 1 : Adding a route This step involves adding a separate route that provides with the generated output of the badges linked with the user account. @router.route('/get_badges', methods=['GET']) def get_badges(): input_data = request.args user = User.getUser(user_id=input_data.get('uid')) badges = Badges().query.filter_by(creator=user) return jsonify(UserBadges(many=True).dump(badges).data) This route allows us to get badges produced by the user as a JSON API data object. This object is fed to the frontend to render the badges as cards. Step 2 : Adding a relevant Schema After creating a route we need to add a relevant schema that will help us to deliver the badges generated by the user to the Ember JS frontend so that it can be consumed as JSON API objects and shown to the user. class UserBadges(Schema): class Meta: type_ = 'user-badges' self_view = 'generateBadges.get_badges' kwargs = {'id': '<id>'} id = fields.Str(required=True, dump_only=True) image = fields.Str(required=True) csv = fields.Str(required=True) badge_id = fields.Str(required=True) text_color = fields.Str(required=True) badge_size = fields.Str(required=True) user_id = fields.Relationship( self_url='/api/upload/get_file', self_url_kwargs={'file_id': '<id>'}, related_url='/user/register', related_url_kwargs={'id': '<id>'}, include_resource_linkage=True, type_='User' ) This is the ‘UserBadge’ schema that produces the output results of the GET request on the route. Finally, once this is done we can fire up a GET request on our deployment to receive results. The command that you need to run is given below. $ ~ curl -X GET http://localhost:5000/api/get_badges?uid={user_id} Further Improvements We are working on adding multiple routes and adding modifications to database models and schemas so that the functionality of Badgeyay can be extended to a large extent. This will help us in making this badge generator even better. Resources The Pull Request for the same : https://github.com/fossasia/badgeyay/pull/949 The Issue for the same : https://github.com/fossasia/badgeyay/issues/948 Read about adding routes Blueprint : http://flask.pocoo.org/docs/1.0/blueprints/ Read about Schemas : https://github.com/marshmallow-code/marshmallow-jsonapi  

Continue ReadingGet My Badges from Badgeyay API

Custom Colored Images with Badgeyay

Backend functionality of any Badge generator is to generate badges as per the requirements of the user. Currently Badgeyay is capable of generating badges by the following way: Adding or Selecting a Pre-defined Image from the given set Uploading a new image and then using it as a background Well, badgeyay has been missing a functionality of generating Custom Colored images. What is meant by Custom Colored Badges? Currently, there are a set of 7 different kind of pre-defined images to choose from. But let’s say that a user want to choose from the images but doesn’t like any of the color. Therefore we provide the user with an additional option of applying custom background-color for their badges. This allows Badgeyay to deliver a more versatile amount of badges than ever before. Adding the functionality to backend Lets see how this functionality has been implemented in the backend of the project. Step 1 :  Adding a background-color route to backend Before generating badges, we need to know that what is the color that the user wants on the badge. Therefore we created a route that gathers the color and saves the user-defined.svg into that particular color. @router.route('/background_color', methods=['POST']) def background_color(): try: data = request.get_json()['data']['attributes'] bg_color = data['bg_color'] except Exception: return ErrorResponse(PayloadNotFound().message, 422, {'Content-Type': 'application/json'}).respond() svg2png = SVG2PNG() bg_color = '#' + str(bg_color) user_defined_path = svg2png.do_svg2png(1, bg_color) with open(user_defined_path, "rb") as image_file: image_data = base64.b64encode(image_file.read()) os.remove(user_defined_path) try: imageName = saveToImage(imageFile=image_data.decode('utf-8'), extension=".png") except Exception: return ErrorResponse(ImageNotFound().message, 422, {'Content-Type': 'application/json'}).respond() uid = data['uid'] fetch_user = User.getUser(user_id=uid) if fetch_user is None: return ErrorResponse(UserNotFound(uid).message, 422, {'Content-Type': 'application/json'}).respond() file_upload = File(filename=imageName, filetype='image', uploader=fetch_user) file_upload.save_to_db() return jsonify(ColorImageSchema().dump(file_upload).data) Step 2: Adding Schema for background-color to backend To get and save values from and to database, we need to have some layer of abstraction and so we use schemas created using marshmallow_jsonapi class ColorImageSchema(Schema): class Meta: type_ = 'bg-color' self_view = 'fileUploader.background_color' kwargs = {'id': '<id>'} id = fields.Str(required=True, dump_only=True) filename = fields.Str(required=True) filetype = fields.Str(required=True) user_id = fields.Relationship( self_url='/api/upload/background_color', self_url_kwargs={'file_id': '<id>'}, related_url='/user/register', related_url_kwargs={'id': '<id>'}, include_resource_linkage=True, type_='User' ) Now we have our schema and route done, So we can move forward with the logic of making badges. Step 3 : Converting the SVG to PNG and adding custom color Now we have the user-defined color for the badge background, but we still need a way to apply it to the badges. It is done using the following code below. def do_svg2png(self, opacity, fill): """ Module to convert svg to png :param `opacity` - Opacity for the output :param `fill` -  Background fill for the output """ filename = os.path.join(self.APP_ROOT, 'svg', 'user_defined.svg') tree = parse(open(filename, 'r')) element = tree.getroot() # changing style using XPath. path = element.xpath('//*[@id="rect4504"]')[0] style_detail = path.get("style") style_detail = style_detail.split(";") style_detail[0] = "opacity:" + str(opacity) style_detail[1] = "fill:" + str(fill) style_detail = ';'.join(style_detail) path.set("style", style_detail) # changing text using XPath. path = element.xpath('//*[@id="tspan932"]')[0] # Saving in the original XML tree etree.ElementTree(element).write(filename, pretty_print=True) print("done") png_name = os.path.join(self.APP_ROOT, 'static', 'uploads', 'image', str(uuid.uuid4())) + ".png" svg2png(url=filename, write_to=png_name) return png_name Finally…

Continue ReadingCustom Colored Images with Badgeyay

Disable editing for non-editable skills for non-admin users

As the Skills in SUSI Skill CMS are publicly editable, any user has the access to edit them. Hence, there needed to be a better control over who can edit the Skills in CMS. We needed to implement a feature to allow Admins and higher user roles to change the status of a Skill to non-editable. The subsequent implementation on CMS would require disabling editing for non-editable Skills for non-admin users. This blog post explains how this feature has been implemented in SUSI.AI. Adding a boolean parameter ‘editable’ to the Skill metadata We needed to add a boolean parameter in the Skill metadata for each Skill. The boolean parameter is ‘editable’. If its value is true, then it implies that editing should be allowed for that Skill. If it is set to false, then the Skill should not be editable for non-admin users. By default, its value has been set to true for all Skills. This is implemented as follows in the SusiSkill.java file: // in the getSkillMetadata() method skillMetadata.put("editable", getSkillEditStatus(model, group, language, skillname)); // declaration of the getSkillEditStatus() method public static boolean getSkillEditStatus(String model, String group, String language, String skillname) { // skill status JsonTray skillStatus = DAO.skillStatus; if (skillStatus.has(model)) { JSONObject modelName = skillStatus.getJSONObject(model); if (modelName.has(group)) { JSONObject groupName = modelName.getJSONObject(group); if (groupName.has(language)) { JSONObject languageName = groupName.getJSONObject(language); if (languageName.has(skillname)) { JSONObject skillName = languageName.getJSONObject(skillname); if (skillName.has("editable")) { return false; } } } } } return true; }   Allowing Admin and higher user roles to change edit status of any Skill This is facilitated by the endpoint ‘/cms/changeSkillStatus.json’. Its minimum base user role is set to Admin so that only Admins and higher user roles are able to change status of any Skill. A sample API call to this endpoint to change the edit status of any Skill to ‘false’ is as follows: http://127.0.0.1:4000/cms/changeSkillStatus.json?model=general&group=Knowledge&language=en&skill=aboutsusi&editable=false&access_token=zdasIagg71NF9S2Wu060ZxrRdHeFAx   If we want to change the edit status of any Skill to ‘false’, then we need to add the Skill to the ‘skillStatus.json’ file. For this, we need to traverse inside the JSONObject in the ‘skillStatus.json’ file. We need to traverse inside the model, group and language as specified in the query parameters. This is done as follows: if(editable.equals("false")) { skill_status.put("editable", false); } JsonTray skillStatus = DAO.skillStatus; if (skillStatus.has(model_name)) { modelName = skillStatus.getJSONObject(model_name); if (modelName.has(group_name)) { groupName = modelName.getJSONObject(group_name); if (groupName.has(language_name)) { languageName = groupName.getJSONObject(language_name); if (languageName.has(skill_name)) { skillName = languageName.getJSONObject(skill_name); if(editable != null && editable.equals("false")) { skillName.put("editable", false); } else if(editable != null && editable.equals("true")) { skillName.remove("editable"); } skillStatus.commit(); result.put("accepted", true); result.put("message", "Skill status changed successfully."); return new ServiceResponse(result); } } } }   If we want to change the edit status of any Skill to ‘true’, then we need to remove the Skill from the ‘skillStatus.json’ file. We also need to remove all the empty JSONObjects inside the ‘skillStatus.json’ file, if they are created in the process of removing Skills from it. This is done as follows: if (skillStatus.has(model_name)) { modelName = skillStatus.getJSONObject(model_name); if (modelName.has(group_name)) { groupName = modelName.getJSONObject(group_name); if…

Continue ReadingDisable editing for non-editable skills for non-admin users

Giving users option to switch between All and Reviewed Only Skills on SUSI Skill CMS

There are a lot of Skills on SUSI Skill CMS. Any registered user has the access to creating his/her own Skills. Hence, we need to give the users an option on SUSI Skill CMS whether they want to see all the Skills, or only those Skills that have been tested thoroughly and have been approved by the Admin and higher user roles. This blog post explains how this feature has been implemented on the SUSI Skill CMS. How is review status of any Skill changed on the server? The API endpoint which allows Admin and higher user roles to change the review status of any Skill on the server is ‘/cms/changeSkillStatus.json’. It takes the following parameters: model: Model of the Skill group: Group of the Skill language: Language of the Skill skill: Skill name reviewed: A boolean parameter which if true, signifies that the Skill has been approved. Sample API call: https://api.susi.ai/cms/changeSkillStatus.json?model=general&group=Knowledge&language=en&skill=aboutsusi&reviewed=true&access_token=yourAccessToken   Fetching reviewed only Skills from the server The ‘/cms/getSkillList.json’ endpoint has been modified to facilitate returning only the Skills whose review status is true. This is done by the following API call: https://api.susi.ai/cms/getSkillList.json?reviewed=true   Creating checkbox to switch between All and Reviewed Only Skills Checkbox is one of the many Material-UI components. Hence, we need to first import it before we can use it directly in our BrowseSkill component. import Checkbox from 'material-ui/Checkbox';   In the constructor of the BrowseSkill class, we set states for two variables as follows: constructor(props) { super(props); this.state = { // other state variables showSkills: '', showReviewedSkills: false, }; }   In the above code for the constructor, we have set two state variables. ‘showSkills’ is a string which can either be an empty string, or ‘&reviewed=true’. We want to append this string to the ‘/cms/getSkillList.json’ API call because it would determine whether we want to fetch All Skills or reviewed only Skills. The second variable ‘showReviewedSkills’ is a boolean used to keep record of the current state of the page. If it is true, then it means that currently, only the reviewed Skills are being displayed on the CMS site. Implementation of the checkbox This is how the Checkbox has been implemented for the purpose of switching between All and Reviewed Only Skills: <Checkbox label="Show Only Reviewed Skills" labelPosition="right" className="select" checked={this.state.showReviewedSkills} labelStyle={{ fontSize: '14px' }} iconStyle={{ left: '4px' }} style={{ width: '256px', paddingLeft: '8px', top: '3px', }} onCheck={this.handleShowSkills} />   As can be seen from the above code, the initial state of the checkbox is unchecked as initially, the value of the state variable ‘showReviewedSkills’ is set to false in the constructor. This means that initially all Skills will be shown to the user. On clicking on the checkbox, handleShowSkills() function is called. Its implementation is as follows: handleShowSkills = () => { let value = !this.state.showReviewedSkills; let showSkills = value ? '&reviewed=true' : ''; this.setState( { showReviewedSkills: value, showSkills: showSkills, }, function() { this.loadCards(); }, ); };   In the handleShowSkills() function, firstly we store the current value of the…

Continue ReadingGiving users option to switch between All and Reviewed Only Skills on SUSI Skill CMS

Fetching Info of All Users and their connected devices for the SUSI.AI Admin Panel

Fetching the data of all users is required for displaying the list of users on the SUSI.AI Admin panel. It was also required to fetch the information of connected devices of the user along with the other user data. The right to fetch the data of all users should only be permitted to user roles “OPERATOR” and above. This blog post explains how the data of connected devices of all users is fetched, which can then be used in the Admin panel. How is user data stored on the server? All the personal accounting information of any user is stored in the user’s accounting object. This is stored in the “accounting.json” file. The structure of this file is as follows: { "email:akjn11@gmail.com": { "devices": { "8C-39-45-23-D8-95": { "name": "Device 2", "room": "Room 2", "geolocation": { "latitude": "54.34567", "longitude": "64.34567" } } }, "lastLoginIP": "127.0.0.1" }, "email:akjn22@gmail.com": { "devices": { "1C-29-46-24-D3-55": { "name": "Device 2", "room": "Room 2", "geolocation": { "latitude": "54.34567", "longitude": "64.34567" } } }, "lastLoginIP": "127.0.0.1" } }   As can be seen from the above sample content of the “accounting.json” file, we need to fetch this data so that it can then be used to display the list of users along with their connected devices on the Admin panel. Implementing API to fetch user data and their connected devices The endpoint of the servlet is “/aaa/getUsers.json” and the minimum user role for this servlet is “OPERATOR”. This is implemented as follows: @Override public String getAPIPath() { return "/aaa/getUsers.json"; } @Override public UserRole getMinimalUserRole() { return UserRole.OPERATOR; }   Let us go over the main method serviceImpl() of the servlet: We need to traverse through the user data of all authorized users. This is done by getting the data using DAO.getAuthorizedClients() and storing them in a Collection. Then we extract all the keys from this collection, which is then used to traverse into the Collection and fetch the user data. The implementation is as follows: Collection<ClientIdentity> authorized = DAO.getAuthorizedClients(); List<String> keysList = new ArrayList<String>(); authorized.forEach(client -> keysList.add(client.toString())); for (Client client : authorized) { // code }   Then we traverse through each client and generate a client identity to get the user role of the client. This is done using the DAO.getAuthorization() method. The user role of the client is also put in the final object which we want to return. This is implemented as follows: JSONObject json = client.toJSON(); ClientIdentity identity = new ClientIdentity(ClientIdentity.Type.email, client.getName()); Authorization authorization = DAO.getAuthorization(identity); UserRole userRole = authorization.getUserRole(); json.put("userRole", userRole.toString().toLowerCase());   Then the client credentials are generated and it is checked whether the user is verified or not. If the user is verified, then in the final object, “confirmed” is set to true, else it is set to false. ClientCredential clientCredential = new ClientCredential (ClientCredential.Type.passwd_login, identity.getName()); Authentication authentication = DAO.getAuthentication(clientCredential); json.put("confirmed", authentication.getBoolean("activated", false));   Then we fetch the accounting object of the user using DAO.getAccounting(), and extract all the user data and put them in separate key value pairs in the final…

Continue ReadingFetching Info of All Users and their connected devices for the SUSI.AI Admin Panel

Implementing a device wise usage section on the skill page

SUSI Skill CMS showcases all the skills on the index page as skill cards and users can visit any skill page for any skill by clicking on any of these cards, skill pages for each skill hold some interesting metrics like rating, usage data, country wise usage data etc. But since SUSI runs on different devices so we need something to distribute and showcase how a skill is performing on each device so we implemented a pie chart for visualization of device wise usage data. About the API An API is developed at the server so from the client we call this API to fetch data from the server and plug this data into the chart we wish to render. Endpoint : /cms/getDeviceWiseSkillUsage.json   Parameters : model group language skill Sample API call : /cms/getDeviceWiseSkillUsage.json?model=general&group=Knowledge&language=en&skill=ceo   Response { "skill_usage": [ { "count": 3, "device_type": "Others" }, { "count": 39, "device_type": "Android" }, { "count": 1, "device_type": "Web Client" } ], "session": {"identity": { "type": "host", "name": "162.158.166.37_35449f1b", "anonymous": true }}, "skill_name": "news", "accepted": true, "message": "Device wise skill usage fetched" } Fetching the data for the chart Setting the URL to fetch data from, this URL will be used to make the AJAX call. let deviceUsageUrl = `${urls.API_URL}/cms/getSkillsByAuthor.json?author_email=${cookies.get('emailId')}`; deviceUsageUrl = deviceUsageUrl + '?model=' + modelValue + '&group=' + this.groupValue + '&language=' + this.languageValue + '&skill=' + this.name;   Make an ajax call to extract data from the response and call a function which saves the data to the application state, this data will later be used to render our chart we wish to render. $.ajax({ url: deviceUsageUrl, ... success: function(data) { if (data.skill_usage) { self.saveDeviceUsageData(data.skill_usage); } }, error: function(e) { self.saveDeviceUsageData(); }, });   Set the application state with the received data which the pie chart component will use as it’s data source. saveDeviceUsageData = (device_usage_data = []) => { this.setState({ device_usage_data, }); }; Implementing the UI We already have a card component for device usage section so we append our device wise usage section to this already present card. We fetch the data in the skillListing component and pass that data as props to the skill usage component so using data from the received props we render our pie chart. Importing the needed components from recharts library. import { Tooltip, Legend, PieChart, Pie, Sector, Cell } from 'recharts';   Rendering the Piechart component with appropriate props, the data props is the most important which is taken from the application state which we saved earlier. <PieChart width={600} height={350}> <Pie data={this.props.device_usage_data} nameKey="device_type" dataKey="count" onMouseEnter={this.onPieEnter} ... > ... </Pie> <Legend wrapperStyle={{ position: 'relative' }} /> </PieChart>   Configuring color for each Cell in the pie so it looks more interactive and we have distinguished colors for all devices. {this.props.device_usage_data.map((entry, index) => ( <Cell key={index} fill={ [ '#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#EA4335', ][index % 5] } /> ))}   Rendering the Pie only when data is available in props so we don’t end up rendering a blank chart which obviously won’t look good. {…

Continue ReadingImplementing a device wise usage section on the skill page