Back

[SOLVED] Create Appwrite function to add username when OAuth signup

  • 0
  • Databases
  • Accounts
  • Web
loup
26 Jun, 2023, 18:55

Mhh for example soundcloud, when u signup with Google, soundcloud choose a username considering ur name

TL;DR
Solution: The user has successfully created an Appwrite function to add a username when signing up with OAuth. The function generates a unique username based on the user's name and checks if a document with the same username already exists in the user collection. If it does, the function returns an error message. If not, the function creates a new document with the user's ID and username. The issue mentioned in the thread is that the user.*.create event is not triggered when creating a user via OAuth. The user attempted to solve this by checking if the user is created with OAuth in a separate function, but the function stops before completing due
loup
26 Jun, 2023, 18:56

I guess there is no function trigger event when someone logs with OAuth?

loup
26 Jun, 2023, 19:04

Twitter too do that like create a default username

Drake
26 Jun, 2023, 19:04

It depends on the app/system. Some apps have usernames, while others rely on email. Appwrite mostly uses emails, especially for oauth

loup
26 Jun, 2023, 19:07

If I make a function triggered by user.*.create Inside I check if a document in the user collection (where extra user data are) exist with the userId just created. If yes (signup with email), return. If not (signup with OAuth), create a default username based on the Name

loup
26 Jun, 2023, 21:31

Well I try to create a function which for the moment only check if a document with the userId of the user just created exist :

TypeScript
const sdk = require("node-appwrite");

module.exports = async function (req, res) {
  const client = new sdk.Client();

  const account = new sdk.Account(client);
  const avatars = new sdk.Avatars(client);
  const database = new sdk.Databases(client);
  const functions = new sdk.Functions(client);
  const health = new sdk.Health(client);
  const locale = new sdk.Locale(client);
  const storage = new sdk.Storage(client);
  const teams = new sdk.Teams(client);
  const users = new sdk.Users(client);
  const query = new sdk.Query();

  if (
    !req.variables['APPWRITE_FUNCTION_ENDPOINT'] ||
    !req.variables['APPWRITE_FUNCTION_API_KEY']
  ) {
    console.warn("Environment variables are not set. Function cannot use Appwrite SDK.");
  } else {
    client
      .setEndpoint(req.variables['APPWRITE_FUNCTION_ENDPOINT'])
      .setProject(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      .setKey(req.variables['APPWRITE_FUNCTION_API_KEY'])
      .setSelfSigned(true);
  }

  const user = JSON.parse(req.variables['APPWRITE_FUNCTION_DATA'])

  async function checkSignupType(id, databaseId, collectionId) {
    try {
      await database.getDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], id);
      return true
    } catch (error) {
      console.error("Error checking signup type:", error);
      return false;
    }
  }

  // const userDocuments = await database.getDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], user.$id);

  const userDocuments = await checkSignupType(user.$id);

  console.log("userDocuments", userDocuments)

};
loup
26 Jun, 2023, 21:33

But Ive got a function error : An internal curl error has occurred within the executor! Error Msg: Operation timed out But if I replace this line: const userDocuments = await checkSignupType(user.$id); By : const userDocuments = await database.getDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"] Ive this output : Error: Document with the requested ID could not be found. But without the console.log

Drake
26 Jun, 2023, 21:35

You must call res.json() or res.send() once before returning

loup
26 Jun, 2023, 21:43

Ohh yes mb that work. In Appwrite Function when we made a return even if its true or false, the function stop ? Because the console.log never read so these returns in the checkSignupType function stop the Appwrite function

Drake
26 Jun, 2023, 21:45

No. The function needs to complete successfully for you to see the logs

loup
26 Jun, 2023, 21:51

That weird because Ive this :

TypeScript
async function checkSignupType(id) {
    try {
      await database.getDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], id);
      console.log('Email')
      res.json()
      return false
    } catch (error) {
      console.log('OAuth')
      res.json()
      return true;
    }
  }

  const isOAuth = await checkSignupType(user.$id);

  console.log("isOAuth", isOAuth)

And in the function logs I can see the console.log('OAuth') and the console.log('Email') but not the last one

loup
26 Jun, 2023, 22:02

Create Appwrite function to add username when OAuth signup

loup
26 Jun, 2023, 22:26

wait when signup with OAuth the user.*.create isnt triggered ?

Drake
26 Jun, 2023, 22:28
Drake
26 Jun, 2023, 22:30

You should probably call res.json last. You should also be passing an object to it

loup
26 Jun, 2023, 22:33

ohh okay sry

loup
26 Jun, 2023, 22:38

Okay I didn't understand that the function stops when res.json is called. Its working !

loup
26 Jun, 2023, 23:32

Well I success to make username generator function for OAuth signups, based on username; there is the code <:appwriterocket:823996226894692403> :

TypeScript
const sdk = require("node-appwrite");

module.exports = async function (req, res) {
  const client = new sdk.Client();

  const database = new sdk.Databases(client);

  if (
    !req.variables['APPWRITE_FUNCTION_ENDPOINT'] ||
    !req.variables['APPWRITE_FUNCTION_API_KEY']
  ) {
    console.warn("Environment variables are not set. Function cannot use Appwrite SDK.");
  } else {
    client
      .setEndpoint(req.variables['APPWRITE_FUNCTION_ENDPOINT'])
      .setProject(req.variables['APPWRITE_FUNCTION_PROJECT_ID'])
      .setKey(req.variables['APPWRITE_FUNCTION_API_KEY'])
      .setSelfSigned(true);
  }
  const user = JSON.parse(req.variables['APPWRITE_FUNCTION_EVENT_DATA'])

  async function handleIsOAuth(id) {
    try {
      await database.getDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], id);
      console.log('User already has a username')
      res.json({ message: 'User already has a username' })
      return false
    } catch (error) {
      console.log('User has no username')
      return true
    }
  }

  async function generateUniqueUsername(name, id, attempt = 1) {
    if (attempt > 5) {
      console.log('Unable to generate a unique username.')
      return id
    }

    let username = name.toLowerCase().replace(/[^A-Za-z0-9_]/g, "");
    username = username.slice(0, 11)
    username += Math.floor(Math.random() * Math.pow(10, (15 - username.length)));

    const checkUsernameAvailability = await database.listDocuments(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], [
      sdk.Query.equal('username', username)
    ]);

    if (checkUsernameAvailability.documents.length > 0) {
      console.log('Username is already in use, generating a new one.')
      return generateUniqueUsername(name, id, attempt + 1);
    }

    return username;
  }

  await handleIsOAuth(user.$id);

  const username = await generateUniqueUsername(user.name, user.$id)

  try {
    await database.createDocument(req.variables["APPWRITE_FUNCTION_DATABASE_ID"], req.variables["APPWRITE_FUNCTION_COLLECTION_ID"], user.$id, {
      "userId": user.$id,
      "username": username
    })
    res.json({ message: 'Username @' + username +' has been created successfully.'})
    return
  } catch (error) {
    res.json({ error: 'Error creating user', error: error })
    return
  }
};
loup
26 Jun, 2023, 23:35

But for now I can't use it until the user.*.create event is triggered when creating a user via OAuth

Drake
27 Jun, 2023, 02:20

You can trigger on create session and check if it's an oauth session and there's no document in your collection

loup
27 Jun, 2023, 07:45

I was thinking of doing this but I don't realize if it will require a lot of server power to check each session. I want to do some less energy intensive things at the server level so ... But if you think it's not a problem I would do that!

loup
27 Jun, 2023, 07:55

Well with the event user.*.sessions.*.create we dont have a the user Name

Drake
27 Jun, 2023, 12:00

You can make an API call for the user

loup
27 Jun, 2023, 12:42

Yeah I get all info with sdk.Users

loup
27 Jun, 2023, 12:42

[SOLVED] Create Appwrite function to add username when OAuth signup

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more