UserPic / Avatar


#1

Hello there! I’m try to make upload avatar function… but i can’t rename file (if upload to public folder)… or i haven’t acces to tmp folder from server :frowning: Can you check my code please…

This is “Profile update: avatar and email”…

async edit ({auth, request, response}) {
    const randomNumber = new Date().getTime()+Math.floor(Math.random() * 1000)
    const profilePic = request.file('profile_pic', {
      types: ['image'],
      size: ['2mb'],
      allowedExtensions: ['jpg', 'png', 'jpeg']
    })

    let name = `${profilePic._clientName}`

    await profilePic.move('uploads'), {
      name: (randomNumber)+'custom-name.jpg'
    }

    if (!profilePic.moved()) {
      return profilePic.error()
    }

    const data = request.only(['email', 'userpic'])
    const user = await auth.getUser()
    const filenName =  `../../uploads/${name}`
    const validation = await validate(data, {
      email: 'required|email|users'
    })

    user.merge({ userpic: filenName })
    user.merge(data)
    await user.save ()

    return response.redirect('/cabinet')
  } 

and i have some problem… i don’t know how check following errors:

  • If file already exists
  • If file imput is empty (if user don’t change avatar, just change email)

Waiting for your reply! Thank you!


Hosting question
#2

@sequendnb you may have figured this out already, but looks like a syntax issue.

change this:

await profilePic.move('uploads'), {
  name: (randomNumber)+'custom-name.jpg'
}

to this:

await profilePic.move('uploads', {
  name: (randomNumber)+'custom-name.jpg'
})

#3

Thanks bro! This is a work solution!


#4

In Laravel, it handles giving it a custom name so it doesnt clash with any of the other files in the folder. Does Adonis have option to handle this custom naming (with auto figured out extension)?


#5

Yes, Laravel does assign it a name if you don’t pass one, but all it is a Str::random(40).

See the hashName() method

You could implement this almost identically in JavaScript

const crypto = use('crypto') // default nodejs module

const str_random = async (length = 40) => {
  let string = ''
  let len = string.length

  if (len < length) {
    let size = length - len
    let bytes = await crypto.randomBytes(size)

    let buffer = new Buffer(bytes)

    string += buffer
      .toString('base64')
      .replace(/[^a-zA-Z0-9]/g, '')
      .substr(0, size)
  }

  return string
}

Something you’ll find out about AdonisJs is that although it takes a lot of inspiration from Laravel it’s not a 1 to 1 copy.

Hope this helps :smiley:


#6

Oh wow interesting thank you very much for that. So even in Laravel it’s not guranteed that a file name crash doesnt happen! Shoots. Looks like we’ll have to do a while loop with random name to ensure it saves.


#7

The answer to that is: kind of. str_random(32) allows for 2.2726578844967513 x 10^57 unique possibilities.

So technically no, it’s not guaranteed that you won’t have a collision, but we can say you won’t have a collision for some time.

Hope this helps :smiley:


#8

Hey! :wave:

I would recommend you to use the package uuid to generate unique identifier.


#9

Or use https://www.npmjs.com/package/cuid if you want unique ids across cluster.


#10

Or unix timestamp can be used as unique ID for this purpose (numbers looks better in URL than random hashes etc. imho)

new Date().toString()