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