Wallpaper Strategy for Meilix Generator

We were first hosting the wallpaper uploaded by user on the Heroku server which was downloaded by the Travis CI which was previous solution for sending wallpaper to the Travis CI, but the problem was that wallpaper was downloaded only when build started building the ISO.

Downloading the hosted wallpaper was not a problem but the problem in that method was that the wallpaper hosted can be changed if another user also starts the build using Meilix Generator and uploads the wallpaper which will replace the previous wallpaper so simultaneous builds was not possible in previous method and resulted in conflicts.

So we thought of a sending the wallpaper to the Travis CI server for that we used base64 to and encoded it to a string using this.

with open(filename,'rb') as f:
    os.environ["Wallpaper"] = str(base64.b64encode(f.read()))[1:]

 

After uploading we send it as a variable to Travis CI and decode it. We will receive a binary file after decoding now we need to detect the mime type of the file and rename it accordingly before applying for that we use a script like this.

#renaming wallpaper according to extension png or jpg
for f in wallpaper; do
    type=$( file "$f" | grep -oP '\w+(?= image data)' )
    case $type in  
        PNG)  newext=png ;;
        JPEG) newext=jpg ;;
        *)    echo "??? what is this: $f"; continue ;;
    esac
    mv "$f" "${f%.*}.$newext"
done

 

After fixing the wallpaper extension we can apply it using the themes by replacing it with the theme wallpaper.

Resources

Base64 python documentation

Continue Reading

Encoding and Decoding Images as Data in UserDefaults in SUSI iOS

In this blog post, I will be explaining how to encode and decode images and save them in UserDefaults so that the image persists even if it is removed from the Photos app. It happens a number of times that images are removed from the gallery by the users which results in the app loosing the image. So, to avoid this, we save the image by encoding it in a data object and save it inside UserDefaults. In SUSI iOS app we simply select an image from the image picker, encode it and save it in UserDefaults. To set the image, we simply fetch the image data from the UserDefaults and decode it to an image.

There are two ways we can do the encoding and decoding process:

  • Using Data object
  • Using Base64 string

For the scope of this tutorial, we will use the Data object.

Implementation Steps

  1. To use the image picker, we need to add permissions to `Info.plist` file.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Susi is requesting to get your current location</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Susi needs to request your gallery access to select wallpaper</string>
  1. Select image from gallery

First, we present an alert which gives an option to select the image from the gallery.

// Show wallpaper options to set wallpaper or clear wallpaper
func showWallpaperOptions() {
  let imageDialog = UIAlertController(title: ControllerConstants.wallpaperOptionsTitle, message: nil, preferredStyle: UIAlertControllerStyle.alert)
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.wallpaperOptionsPickAction, style: .default, handler: { (_: UIAlertAction!) in
  imageDialog.dismiss(animated: true, completion: nil)
  self.showImagePicker()
  }))
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.wallpaperOptionsNoWallpaperAction, style: .default, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
    self.removeWallpaperFromUserDefaults()
  }))
  imageDialog.addAction(UIAlertAction(title: ControllerConstants.dialogCancelAction, style: .cancel, handler: { (_: UIAlertAction!) in
    imageDialog.dismiss(animated: true, completion: nil)
  }))
  self.present(imageDialog, animated: true, completion: nil)
}

Here, we create and UIAlertController with three options to select, one which presents the image picker controller, the second one removes the background wallpaper and the third dismisses the alert.

  1. Set the image as background view
// Callback when image is selected from gallery
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
  dismiss(animated: true, completion: nil)
  let chosenImage = info[UIImagePickerControllerOriginalImage] as? UIImage
  if let image = chosenImage {
    setBackgroundImage(image: image)
  }
}

We use the `didFinishPickingMediaWithInfo` delegate method to set the image as background. First we get the image using the the `info` dictionary using the `UIImagePickerControllerOriginalImage` key.

  1. Save the image in UserDefaults (encoding)
// Save image selected by user to user defaults
func saveWallpaperInUserDefaults(image: UIImage!) {
  let imageData = UIImageJPEGRepresentation(image!, 1.0)
  let defaults = UserDefaults.standard
  defaults.set(imageData, forKey: userDefaultsWallpaperKey)
}

We first convert the image to a data object using the `UIImageJPEGRepresentation` method followed by saving the data object in UserDefaults with the key `wallpaper`.

  1. Decode the data object back to UIImage 

Now whenever we need to decode the image, we simply get the data object from the UserDefaults and use it to display the image.

// Check if user defaults have an image data saved else return nil/Any
func getWallpaperFromUserDefaults() -> Any? {
  let defaults = UserDefaults.standard
  return defaults.object(forKey: userDefaultsWallpaperKey)
}

Below is the output when an image is selected and displayed as a background.

Resources:

Continue Reading

Flask App to Upload Wallpaper On the Server for Meilix Generator

We had a problem of getting a wallpaper from the user using Meilix Generator and use the wallpaper with the Meilix build scripts to generate the ISO. So, we were required to host the wallpaper on the server and downloaded by Travis CI during the build to include it in the ISO.

A solution is to render HTML templates and access data sent by POST using the request object from the flask. Redirect and url_for will be used to redirect the user once the upload is done and send_from_directory will help us to host the file under the /uploads that the user just uploaded which will be downloaded by the Travis for building the ISO.

We start by creating the HTML form marked with enctype=multipart/form-data.

<form action="upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file"><br /><br />
        <input type="submit" value="Upload">
 </form>

 

First, we need imports of modules required. Most important is werkzeug.secure_filename().

import os
from flask import Flask, render_template, request, redirect, url_for, send_from_directory
from werkzeug import secure_file

 

Now, we’ll define where to upload and the type of file allowed for uploading. The path to upload directory on the server is defined by the extensions in app.config which is uploads/ here.

app.config['UPLOAD_FOLDER'] = 'uploads/'
app.config['ALLOWED_EXTENSIONS'] = set(['png', 'jpg', 'jpeg'])

 

This functions will check for valid extension for the wallpaper which are png, jpg and jpeg in this case defined above in app.config.

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']

 

After, getting the name of uploaded file from the user then using above function check if there are allowed file type and store it in a variable filename after that it move the files to the upload folder to save it.

Upload function check if the file name is safe and remove unsupported characters (line 3) after that moves it from a temporal folder to the upload folder. After moving, it renames the file as wallpaper so that the download link is same always which we have used in Meilix build script to download from server.

def upload():
    file = request.files['file']
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
         os.rename(UPLOAD_FOLDER + filename, UPLOAD_FOLDER+'wallpaper')
         filename = 'wallpaper'

 

At this point, we have only uploaded the wallpaper and renamed the uploaded file to ‘wallpaper’ only. We cannot access the file outside the server it will result in 403 error so to make it available, the uploaded file need to be registered and then hosted using below code snippet.

We can also register uploaded_file as build_only rule and use the SharedDataMiddleware.

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'],filename)

The hosted wallpaper is used by Meilix in Travis CI to generate ISO using the download link which remains same for the uploaded wallpaper.

Why should we use secure secure_filename() function?

just imagine someone sends the following information as the filename to your app.

filename = "../../../../home/username/.sh"

 

If the number of ../ is correct and you would join this with your UPLOAD_FOLDER the hacker might have the ability to modify a file on the server’s filesystem that he or she should not modify.

Now, let’s look how the function works.

secure_filename('../../../../home/username/.sh')
'home_username_.sh'

Improving the uploads

We can add validation to the size of the file to be uploaded so that in case a user tries to upload a file too much big that may increase load on the server.

from flask import Flask, Request
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024

Resources

Continue Reading

Implementing Wallpapers in React JS SUSI Web Chat Application

The different SUSI AI clients need to match in their feature set. One feature that was missing in the React JS SUSI Web Chat application was the ability for users to change the application wallpaper or background. This is how we implemented it on SUSI Web Chat.
Firstly we added a text field after the circle picker that change the color of the Application body. Because there should be a place to add the wallpaper image URL. Added that text field like this.

   const components = componentsList.map((component) => {
       return

key={component.id} className=‘circleChoose’>

Change color of {component.name}:

 

         color={component} width={'100%'}
         onChangeComplete={ this.handleChangeComplete.bind(this,
         component.component) }
         onChange={this.handleColorChange.bind(this,component.id)}>
       

CirclePicker shows the circular color picker to choose the colors for each component of the application.

        
         name="backgroundImg"
         style={{display:component.component==='body'?'block':'none'}}
         onChange={
           (e,value)=>
           this.handleChangeBackgroundImage(value) }
         value={this.state.bodyBackgroundImage}
          floatingLabelText="Body Background Image URL" />
       

})

In ’TextField’ I have checked below condition whether to display or not to display the text field after the ‘body’ color picker.

style={{display:component.component==='body'?'block':'none'}}

To apply changes as soon as the user enters the image url, we refer the value of the ‘TextField’ and pass it into the ‘handleChangeBackgroundImage()’ function as ‘value’ on change like this.

         onChange={
           (e,value)=>
           this.handleChangeBackgroundImage(value) }

In ‘‘handleChangeBackgroundImage()’ function we change the state of the application and background of the application like this.

  handleChangeBackgroundImage(backImage){
   document.body.style.setProperty('background-image', 'url('+ backImage+')');
   document.body.style.setProperty('background-repeat', 'no-repeat');
   document.body.style.setProperty('background-size', 'cover');
   this.setState({bodyBackgroundImage:backImage});
 }

In here ‘document.body.style.setProperty’ we change the style of the application’s ‘’ tag. This is how wallpapers are changing on SUSI Web Chat Application.

Resources:

React Refs: https://facebook.github.io/react/docs/refs-and-the-dom.html

Refer Value from text field: https://stackoverflow.com/questions/43960183/material-ui-component-reference-does-not-work

Continue Reading
Close Menu