Python / JS Full Stack Developer for Eventyay Project

Location: Remote
Type: Job or Contract (Minimum Duration: 3 months)
Organization: FOSSASIA

Are you passionate about open-source development and enjoy working across the stack and infrastructure? Join FOSSASIA, a global community advancing technology through open-source projects. We’re offering an exciting internship opportunity for a Fullstack Developer with DevOps expertise to contribute to the Eventyay platform—an open-source event management system powering ticketing, speaker management, and virtual events.

If you thrive in a collaborative environment and are eager to tackle development challenges independently while leveraging AI tools to speed up workflows, we’d love to hear from you.

Apply Here


Responsibilities

  • Frontend and Backend Development:

    • Build and maintain responsive user interfaces for Eventyay Tickets, Talk, and Video using Vue.js and Django.

    • Implement and refine APIs and backend systems with guidance from senior developers.

    • Use AI tools (e.g., GitHub Copilot, ChatGPT) to enhance development efficiency.

    • Debug and resolve issues independently with minimal supervision.

  • DevOps and Infrastructure Support:

    • Learn to set up and maintain basic deployment pipelines for CI/CD.

    • Assist in managing cloud infrastructure under guidance.

    • Explore and implement containerization using Docker for specific use cases.

    • Monitor system performance and assist in troubleshooting using tools like Sentry and Grafana.

  • Collaboration and Documentation:

    • Work closely with team members to integrate features and resolve issues collaboratively.

    • Document development processes and write clear instructions for future use.


Requirements

  • Development Skills:

    • Basic knowledge of Vue.js, Django, and REST API development.

    • Familiarity with HTML, CSS, and JavaScript.

    • Experience with programming projects during university or personal initiatives.

  • AI Tool Proficiency:

    • Ability to use AI tools like GitHub Copilot or ChatGPT to accelerate coding and problem-solving.

  • DevOps Fundamentals:

    • Exposure to Docker and basic CI/CD workflows.

    • Understanding of cloud platforms like Hetzner or AWS (hands-on experience is a plus).

    • Comfort with Linux command-line basics and scripting (e.g., Bash, Python).

  • Collaboration and Initiative:

    • Ability to work independently while seeking guidance when needed.

    • Familiarity with Git and version control workflows.

    • Interest in open-source contributions and adherence to FOSSASIA Best Practices.


Relevant Repositories


Why Join Us?

  • Attractive Internship Compensation: Receive an attractive package that reflects your skills and contributions.
  • Open Source Innovation: Work on impactful, community-driven projects that make a difference.
  • Global Team: Collaborate with a talented, diverse group of individuals worldwide.
  • Flexible Work Environment: Enjoy remote work and a flexible schedule.
  • Skill Development: Gain hands-on experience in fullstack development and DevOps while leveraging AI tools.

How to Apply

If you’re excited to take on both development and DevOps responsibilities in a dynamic open-source project, submit your application via this form:

Include:

  1. Your CV/Resume.

  2. Brief info explaining your interest in the internship.

  3. Links to your GitHub/Portfolio or examples of previous work (if available).


Join FOSSASIA as an intern and help shape the future of event management technology with the Eventyay platform!

Continue ReadingPython / JS Full Stack Developer for Eventyay Project

Reducing the YouTube response time by 90%

In this blog post, we are going to cover how the audio from Youtube is being used in SUSI Smart Speaker and how we reduced the response time from ~40 seconds to ~4 seconds for an average music video length.

First Approach

Earlier, we were using MPV player’s inbuilt feature to fetch the YouTube music. However, MPV player was a bulky option and the music server had to be started every time before initiating a music video.

video_process = subprocess.Popen([‘mpv’, ‘–no-video’, ‘https://www.youtube.com/watch?v=’ + video_url[4:], ‘–really-quiet’]) # nosec #pylint-disable type: ignore requests.get(‘http://localhost:7070/song/’ + video_url) self.video_process = video_process stopAction.run() stopAction.detector.terminate()

Making it Efficient

To reduce the response time, we created a custom Music Server based on Flask,python-vlc and python-pafy which accepts requests from the main client and instructs the System to play the music with just 90% more efficiency.

app = Flask(__name__)

Instance = vlc.Instance(‘–no-video’)

player = Instance.media_player_new()

url = @app.route(‘/song’, methods=[‘GET’])

def youtube():

    vid = request.args.get(‘vid’)

    url = ‘https://www.youtube.com/watch?v=’ + vid

    video = pafy.new(url)
    streams = video.audiostreams 

    best = streams[3]

    playurl = best.url

    Media = Instance.media_new(playurl)

    Media.get_mrl()

    player.set_media(Media)

    player.play()

    display_message = {“song”:“started”}

    resp = jsonify(display_message)

    resp.status_code = 200

    return resp

However, shifting to this Server removed the ability to process multiple queries and hence we were unable to pause/play/stop the music until it completed the time duration. We wanted to retain the ability to have ‘play/pause/stop’ actions without implementing multiprocessing or multithreading as it would’ve required extensive testing to successfully implement them without creating deadlocks and would’ve been overkill for a simple feature.

Bringing Back the Lost Functionalities

The first Step we took was to remove the vlc-python module and implement a way to obtain an URL that we use in another asynchronous music player.

@app.route(‘/song’, methods=[‘GET’])
def youtube():

    vid = request.args.get(‘vid’)

    streams = video.audiostreams

    best = streams[3]

    playurl = best.url 

    display_message = {“song”: “started”, “url”: playurl}

    resp = jsonify(display_message)

    resp.status_code = 200

    return resp

The next issue was to actually find a way to run the Music Player asynchronously. We used the `subprocess. Popen` method and cvlc to play the songs asynchronously.

try:

    x = requests.get(‘http://localhost:7070/song?vid=’ + video_url[4:])

    data = x.json()

    url = data[‘url’]

    video_process = subprocess.Popen([‘cvlc’, ‘http’ + url[5:], ‘–no-video’])

    self.video_process = video_process

except Exception as e:

    logger.error(e);

And this is how we were able to increase the efficiency of the music player while maintaining the functionalities.

References

Continue ReadingReducing the YouTube response time by 90%

Modifying Allowed Usage for a User

Badgeyay has been progressing in a very good pace. There are a lot of features being developed and modified in this project. One such feature that has been added is the increasing allowed usage of a user by an admin.

What is Allowed Usage?

Allowed usage is an integer associated with a particular user that determines the number of badges that a person can generate using a single email id. This will allow us to keep track of the number of badges being produced by a particular ID and all.

Modifying the Allowed Usage

This feature is basically an Admin feature, that will allow an admin to increase or decrease the allowed usage of a particular user. This will ensure that if incase a particular user has his/her usage finished, then by contacting the admin, he/she can get the usage refilled.

Adding the functionality

The functionality required us to to add two things

  • A schema for modifying allowed user
  • A route in backend to carry out the functionality

So, Let us start by creating the schema

class UserAllowedUsage(Schema):
class Meta:
type_ =
‘user_allowed_usage’
kwargs = {
‘id’: ‘<id>’}

id = fields.Str(required=True, dump_only=True)
allowed_usage = fields.Str(required=
True, dump_only=True)

Once we have our schema created, then we can create a route to modify the allowed usage for a particular user.

This route will be made accessible to the admin of Badgeyay.

@router.route(‘/add_usage’, methods=[‘POST’])
def admin_add_usage():
try:
data = request.get_json()[
‘data’]
print(data)
except Exception:
return ErrorResponse(JsonNotFound().message, 422, {‘Content-Type’: ‘application/json’}).respond()

uid = data[‘uid’]
allowed_usage = data[
‘allowed_usage’]
user = User.getUser(user_id=uid)
user.allowed_usage = user.allowed_usage + allowed_usage
db.session.commit()

return jsonify(UserAllowedUsage().dump(user).data)

The add_usage route is given above. We can use this route to increase the usage of a particular user.

Given below is an image that shows the API working.

Resources

Continue ReadingModifying Allowed Usage for a User

Voltage Measurement through Channels in PSLab

The Pocket Science Lab multimeter has got three channels namely CH1,CH2 and CH3 with different ranges for measuring the voltages.This blog will give a brief description on how we measure voltages in channels.

Measuring Voltages at channels can be divided into three parts:-

        1. Communication between between device and Android.
        2. Setting up analog channel (analog constants)
        3. Voltage measuring function of android.

Communication between PSLab device and Android App

The communication between the PSLab device and  Android occurs through the help of UsbManger package of CommunicationHandler class of the app. The main two functions involved in the communication are read and write functions in which we send particular number of bytes and then we receive certain bytes.

The read function :-

public int read(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOException {
    int numBytesRead = 0;
    //synchronized (mReadBufferLock) {
    int readNow;
    Log.v(TAG, "TO read : " + bytesToBeRead);
    int bytesToBeReadTemp = bytesToBeRead;
    while (numBytesRead < bytesToBeRead) {
        readNow = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, bytesToBeReadTemp, timeoutMillis);
        if (readNow < 0) {
            Log.e(TAG, "Read Error: " + bytesToBeReadTemp);
            return numBytesRead;
        } else {
            //Log.v(TAG, "Read something" + mReadBuffer);
            System.arraycopy(mReadBuffer, 0, dest, numBytesRead, readNow);
            numBytesRead += readNow;
            bytesToBeReadTemp -= readNow;
            //Log.v(TAG, "READ : " + numBytesRead);
            //Log.v(TAG, "REMAINING: " + bytesToBeRead);
        }
    }
    //}
    Log.v("Bytes Read", "" + numBytesRead);
    return numBytesRead;
}

Similarly the write function is –

public int write(byte[] src, int timeoutMillis) throws IOException {
    if (Build.VERSION.SDK_INT < 18) {
        return writeSupportAPI(src, timeoutMillis);
    }
    int written = 0;
    while (written < src.length) {
        int writeLength, amtWritten;
        //synchronized (mWriteBufferLock) {
        writeLength = Math.min(mWriteBuffer.length, src.length - written);
        // bulk transfer supports offset from API 18
        amtWritten = mConnection.bulkTransfer(mWriteEndpoint, src, written, writeLength, timeoutMillis);
        //}
        if (amtWritten < 0) {
            throw new IOException("Error writing " + writeLength +
                " bytes at offset " + written + " length=" + src.length);
        }
        written += amtWritten;
    }
    return written;
}

Although these are the core functions used for communication but the data received through these functions are further processed using another class known as PacketHandler. In the PacketHandler class also there are two major functions i.e sendByte and getByte(), these are the main functions which are further used in other classes for communication.

The sendByte function:-

public void sendByte(int val) throws IOException {
    if (!connected) {
        throw new IOException("Device not connected");
    }
    if (!loadBurst) {
        try {
            mCommunicationHandler.write(new byte[] {
                (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
            }, timeout);
        } catch (IOException e) {
            Log.e("Error in sending int", e.toString());
            e.printStackTrace();
        }
    } else {
        burstBuffer.put(new byte[] {
            (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
        });
    }
}

As we can see that in this function also the main function used is the write function of communicationHandler but in this class the data is further processed.

Setting Up the Analog Constants

For setting up the ranges, gains and other properties of channels, a different class of AnalogConstants is implemented in the android app, in this class all the properties which are used by the channels are defined which are further used in the sendByte() functions for communication.

public class AnalogConstants {

    public double[] gains = {1, 2, 4, 5, 8, 10, 16, 32, 1 / 11.};
    public String[] allAnalogChannels = {"CH1", "CH2", "CH3", "MIC", "CAP", "SEN", "AN8"};
    public String[] biPolars = {"CH1", "CH2", "CH3", "MIC"};
    public Map<String, double[]> inputRanges = new HashMap<>();
    public Map<String, Integer> picADCMultiplex = new HashMap<>();

    public AnalogConstants() {

        inputRanges.put("CH1", new double[]{16.5, -16.5});
        inputRanges.put("CH2", new double[]{16.5, -16.5});
        inputRanges.put("CH3", new double[]{-3.3, 3.3});
        inputRanges.put("MIC", new double[]{-3.3, 3.3});
        inputRanges.put("CAP", new double[]{0, 3.3});
        inputRanges.put("SEN", new double[]{0, 3.3});
        inputRanges.put("AN8", new double[]{0, 3.3});

        picADCMultiplex.put("CH1", 3);
        picADCMultiplex.put("CH2", 0);
        picADCMultiplex.put("CH3", 1);
        picADCMultiplex.put("MIC", 2);
        picADCMultiplex.put("AN4", 4);
        picADCMultiplex.put("SEN", 7);
        picADCMultiplex.put("CAP", 5);
        picADCMultiplex.put("AN8", 8);

    }
}

Also in the AnalogInput sources class many other properties such as CHOSA( a variable assigned to denote the analog to decimal conversion constant of each channel) are also defined

public AnalogInputSource(String channelName) {
    AnalogConstants analogConstants = new AnalogConstants();
    this.channelName = channelName;
    range = analogConstants.inputRanges.get(channelName);
    gainValues = analogConstants.gains;
    this.CHOSA = analogConstants.picADCMultiplex.get(channelName);
    calPoly10 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 1023,
        0.
    });
    calPoly12 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 4095,
        0.
    });
    if (range[1] - range[0] < 0) {
        inverted = true;
        inversion = -1;
    }
    if (channelName.equals("CH1")) {
        gainEnabled = true;
        gainPGA = 1;
        gain = 0;
    } else if (channelName.equals("CH2")) {
        gainEnabled = true;
        gainPGA = 2;
        gain = 0;
    }
    gain = 0;
    regenerateCalibration();
}

Also in this constructor a polynomial function is also called which further plays an important  role in measuring voltage as it is through this polynomial function we get the voltage of channels in the science lab class , also it is also used in oscilloscope for plotting the graph . So this was the setup of analog channels.

Voltage Measuring Functions

There are two major functions for measuring voltages which are present in the scienceLab class

  • getAverageVoltage
  • getRawableVoltage

Here are the functions

private double getRawAverageVoltage(String channelName) {
    try {
        int chosa = this.calcCHOSA(channelName);
        mPacketHandler.sendByte(mCommandsProto.ADC);
        mPacketHandler.sendByte(mCommandsProto.GET_VOLTAGE_SUMMED);
        mPacketHandler.sendByte(chosa);
        int vSum = mPacketHandler.getVoltageSummation();
        mPacketHandler.getAcknowledgement();
        return vSum / 16.0;
    } catch (IOException | NullPointerException e) {
        e.printStackTrace();
        Log.e(TAG, "Error in getRawAverageVoltage");
    }
    return 0;
}

This is the major function which takes the data from the communicationHandler class via packetHandler. Further this function is used in the getAverageVoltage function.

private double getAverageVoltage(String channelName, Integer sample) {
    if (sample == null) sample = 1;
    PolynomialFunction poly;
    double sum = 0;
    poly = analogInputSources.get(channelName).calPoly12;
    ArrayList < Double > vals = new ArrayList < > ();
    for (int i = 0; i < sample; i++) {
        vals.add(getRawAverageVoltage(channelName));
    }
    for (int j = 0; j < vals.size(); j++) {
        sum = sum + poly.value(vals.get(j));
    }
    return sum / vals.size();
}

This function uses the data from the getRawableVoltage function and uses it the polynomial generated in the analog lasses to calculate the final voltage. Thus this was the core backend of calculating the voltages through channels in PSLab.

Resources:

Continue ReadingVoltage Measurement through Channels in PSLab

Implementing Badgename Update Functionality

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay has many features related to enhancement in generation of badges. It gives choice of uploading data entries i.e by CSV or manually. There are options available for choosing Badge Background and font specifications. Now the next important thing from User perspective is that there should be a feature in My badges panel where user can see all badges & other details  and should be able to edit them if he want to, so moving forward with this feature I have implemented Badge Name update functionality in the frontend.

In this blog, I will be discussing how I implemented Update Badge Name functionality in my Pull Request so that the User can change his Badge Name  at any point of time in my badges panel.

Let’s get started and understand it step by step.

Step 1:

Create Badge Name component with Ember CLI.

$ ember g component badge-name

 

Step 2:

Make changes in Handlebar of Badge Name. We will be using semantic UI form for making the changes in Handlebars.

<form class="ui form" {{action 'updateBadgeName' on="change"}}>
    
class="ui icon input"> class="pen square icon"> {{input type="text" value=badge.badge_name }}
</form>

 

We have used action on submitting the Form for changing and updating the Badgename in Database.

Step 3:

We will now define the action in badge name JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
import Ember from 'ember';
const { inject } = Ember;
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  notifications : inject.service('notification-messages'),
  actions       : {
    updateBadgeName() {
      this.get('sendBadgeName')(this.get('badge'));
    },
    didRender() {
      this.$('.ui.form')
        .form({
          inline : true,
          delay  : false,
          fields : {
            Name: {
              identifier : 'Name',
              rules      : [
                {
                  type   : 'empty',
                  prompt : 'Please enter a valid Badge Name'
                }
              ]
            }
          }
        });
    }
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
  routing       : service('-routing'),
  notifications : service('notification-messages'),
  actions       : {
    updateBadgeName(badge) {
      badge.save()
        .then(() => this.get('notifications').success('Badge Name Successfully Updated!', {
          autoClear     : true,
          clearDuration : 1500
        }));
    }
  }
});

 

Now, I am done with doing all the changes in Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • My Badges Panel

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk

 

Continue ReadingImplementing Badgename Update Functionality

Implementing Different Alignment for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing different text alignment  for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented different text alignment for Different Line in Badgeyay Backend in my Pull Request.

To implement different text alignment for Different Line feature,  first, the component in SVG that is determining the text alignment of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font type for the badge is text-align and its default value is set to start(right alignment). If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the text-align value from the frontend.
  • Using the same for the text-align in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to text-align property provided by the User in the Frontend.

 def change_text_align(self,
                          filename,
                          badge_size,
                          paper_size,
                          align_1, // Values from Frontend
                          align_2,
                          align_3,
                          align_4,
                          align_5):

        """
            Module to change Text Alignment of each badge line
                :param `filename` - svg file to modify.
                :param `align_1` - Text Alignment to be applied on first line
                :param `align_2` - Text Alignment to be applied on Second line
                :param `align_3` - Text Alignment to be applied on Third line
                :param `align_4` - Text Alignment to be applied on Fourth line
                :param `align_5` - Text Alignment to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        align = [1, align_1, align_2, align_3, align_4, align_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'text-align':
                        style_detail[ind] = "text-align:" + align[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("text-align", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
 // Fill the text-align argument of the selected object by changing the value of text-align.
                    text_style_detail[-1] = "text-align:" + align[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Text Alignment Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different text-align embedded.

Now, we are done with implementation of different text alignment  for Different Line in Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Alignment for Different Line

Implementing Different Font Type for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font types for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font types for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font type for Different Line feature,  first, the component in SVG that is determining the font of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font type for the badge is font-family and its default value is set to sans-serif. If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the font-type value from the frontend.
  • Using the same for the font-type in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font type provided by the User in the Frontend.

  def change_font_family(self,
                           filename,
                           badge_size,
                           paper_size,
                           Font_1, // Values from Frontend
                           Font_2, 
                           font_3,
                           font_4,
                           font_5):

        """
            Module to change Font Family of each badge lines
                :param `filename` - svg file to modify.
                :param `font_1` - Family to be applied on first line
                :param `font_2` - Family to be applied on Second line
                :param `font_3` - Family to be applied on Third line
                :param `font_4` - Family to be applied on Fourth line
                :param `font_5` - Family to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font = [1, font_1, font_2, font_3, font_4, font_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
               //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)
                path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-family':
                        style_detail[ind] = "font-family:" + font[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-family", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
  // Fill the font family argument of the selected object by changing the value of font-family.
                    text_style_detail[-1] = "font-family:" + font[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Family Saved!")

 

After all the changes, the Updated SVG is used for Badge Generation with different font type embedded.

Now, we are done with implementation of Different Font type for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link
  6. Pull Request Link – Link
Continue ReadingImplementing Different Font Type for Different Line

Implementing Different Font Size for Different Line

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Now to provide more freedom to the user in generation of badges, I have worked on feature which will provide user more freedom in choosing font sizes for different lines and create badges more creatively.

In this Blog, I will be discussing how I implemented Different Font Size for Different Line in Badgeyay Backend in my Pull Request.

To implement Different Font Size for Different Line feature,  first, the component in SVG that is determining the font size of the label has to be identified. The label that determines the text on the badge is the <text> label and within it, the label that determines the properties of the text is <tspan>. So mainly we need to alter the properties in the tspan.

The property that determines the font size for the badge is font-size and its default value is set to 31.25 px. If the property in the labels changed, then we can see the corresponding changes in the PDF generated from the svg.

Now the challenges were:

  • To Determine the font-size value from the frontend.
  • Using the same for the font-size in SVG..
  • Changing the built SVG accordingly.

In this Blog, I will be dealing with changing the SVG in Backend according to Font Size provided by the User in the Frontend.

def change_font_size(self,
                         filename,
                         badge_size,
                         paper_size,
                         Font_size_1, // Values from Frontend
                         font_size_2,
                         font_size_3,
                         font_size_4,
                         font_size_5):

        """
   Module to change size of each badge lines
   :param `filename` - svg file to modify.
   :param `font_size_1` - Size to be applied on first line
   :param `font_size_2` - Size to be applied on Second line
   :param `font_size_3` - Size to be applied on Third line
   :param `font_size_4` - Size to be applied on Fourth line
   :param `font_size_5` - Size to be applied on Fifth line
        """
// Storing the Values passed altogether in a list.
        font_size = [1, font_size_1, font_size_2, font_size_3, font_size_4, font_size_5]
// Selecting the dimension config based on the parameters passed in the function.
        dimensions = badge_config[paper_size][badge_size]
        if config.ENV == 'LOCAL':
            filename = 'static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        else:
            filename = os.getcwd() + '/api/static/badges/' + dimensions.badgeSize + 'on' + dimensions.paperSize + '.svg'
        tree = etree.parse(open(os.path.join(self.APP_ROOT, filename), 'r'))
        element = tree.getroot()

        for idx in range(1, dimensions.badges + 1):

            for row in range(1, 6):
                 //Selecting the text element with the ID
                _id = 'Person_color_{}_{}'.format(idx, row)                 path = element.xpath(("//*[@id='{}']").format(_id))[0]
                style_detail = path.get("style")
                style_detail = style_detail.split(";")

                for ind, i in enumerate(style_detail):
                    if i.split(':')[0] == 'font-size':
                        style_detail[ind] = "font-size:" + font_size[row]
                style_detail = ';'.join(style_detail)
                text_nodes = path.getchildren()
                path.set("font-size", style_detail)

                for t in text_nodes:
                    text_style_detail = t.get("style")
                    text_style_detail = text_style_detail.split(";")
   // Fill the font size argument of the selected object by changing the value of font-size.
                    text_style_detail[-1] = "font-size:" + font_size[row]
                    text_style_detail = ";".join(text_style_detail)
                    t.set("style", text_style_detail)

        etree.ElementTree(element).write(filename, pretty_print=True)
        print("Font Size Saved!")

 

 

After all the changes, the Updated SVG is used for Badge Generation with different font size embedded

Now, we are done with implementation of Different Font Size for Different Line in

Badgeyay Backend.

Resources:

  1. Extracting map information from the SVG –  Link
  2. LXML documentation – Link
  3. Parsing the SVG – Link
  4. Badgeyay Repository – Link
  5. Issue Link – Link

Pull Request Link – Link

Continue ReadingImplementing Different Font Size for Different Line

Implementing Password Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Password functionality in my Pull Request so that the User can change his Password at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User Password component with help of ember cli.

Step 2:

Make changes in Handlebar of User Password. We will be using semantic UI form for making the changes in Handlebars.

<h2 class="ui header">Password</h2>
<h5 class="ui dividing header">Change your password.</h5>
<form class="ui form" {{action 'updateUserPassword' on="submit"}}>
    
class="field"> New Password
class="fields">
class="ten wide field"> {{input type="password" id="newPassword" name=newPassword value=user.password}}
</div> </div>
class="field"> Verify Password
class="fields">
class="ten wide field"> {{input type="password" id="newPasswordVerify" name=newPasswordVerify placeholder="Re-enter Password"}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0"> Save Changes </button> </form>

 

We have used action on submitting the Form for changing and updating the Password in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserPassword() {
      let password = this.get('newPassword');
      this.get('sendUserPassword')(password);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          newPassword: {
            identifier : 'newPassword',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a password'
              },
              {
                type   : 'minLength[6]',
                prompt : 'Your password must have at least {ruleValue} characters'
              }
            ]
          },
          newPasswordVerify: {
            identifier : 'newPasswordVerify',
            rules      : [
              {
                type   : 'match[newPassword]',
                prompt : 'Passwords do not match'
              }
            ]
          }
        }
      });
  }
});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

.......
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
...............
   updateUserPassword() {
      this.get('user').save()
        .then(() => this.get('notify').success('Password Successfully Updated!'))
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if Password changes in params, It should change the password and send the response with the updated user schema.

api/controllers/registerUser.py
...............
   if 'password' in data.keys():
        user.password = data['password']
        update_firebase_password(user.id, user.password)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

  • User password Panel

Now, we are done with implementation of Update password Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing Password Update Functionality

Implementing User-name Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and the most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Username functionality in my Pull Request so that the User can change his username at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User account component with help of ember cli.

$ ember g component user-component/user-account

 

Step 2:

Make changes in Handlebar of User Account. We will be using semantic UI form for making the changes in Handlebars.

// user-account.hbs

<h2 class="ui dividing header">Account</h2>
<form class="ui form" {{action 'updateUserName' on="submit"}}>
    
class="ui field"> Username
class="ui fields">
class="ten wide field"> {{input type="text" id="profileName" name=profileName value=user.username}}
</div> </div>
class="ui field"> Email
class="ui fields">
class="ten wide disabled field"> {{input type="email" name=email value=user.email}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0" >Save Changes</button> </form>

 

We have used action on submitting the Form for changing and updating the username in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserName() {
      let profileName = this.get('profileName');
      this.get('sendUserName')(profileName);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          username: {
            identifier : 'profileName',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a valid username'
              }
            ]
          }
        }
      });
}});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

…….
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
…………...
   updateUserName(profileName) {
      const _this = this;
      const user = this.get('store').peekAll('user');
      user.forEach(user_ => {
        _this.set('uid', user_.get('id'));
      });
      _this.get('user').save();
      _this.get('notify').success('Username Successfully Updated!');
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if username is change in params, It should change the username and send the response with the updated username.

api/controllers/registerUser.py
…………...
   if 'username' in data.keys():
        user.username = data['username']
        update_firebase_username(user.id, user.username)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

User Account Panel

Now, we are done with implementation of Update Username Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing User-name Update Functionality