#[SOLVED] Add a default team for new User and adding verified role for verified email account

148 messages · Page 1 of 1 (latest)

unborn goblet
#

My goal is to create a function which give a default team for new user call 'user' Team. And when the user verify his email, another function gave him the role 'verified'

rich socket
#

You'll need to create two functions.

  1. On user create
  2. On user verified

If you look here
https://appwrite.io/docs/functions#functionVariables
You can see the list of all the variables that can be sent to your function.

Additionally, you can add custom variables like APPWRITE_FUNCTION_PROJECT_ID for example in your function Settings page.

unborn goblet
rich socket
#

When accessing Appwrite
You can do it in one of two ways:

In function you'll usaully use the Server side.
The server side has much more capabilities and no rate-limit on number of requests.

But, for that you'll need to create an Api key in the project overview page.
https://appwrite.io/docs/keys

unborn goblet
rich socket
#

In your case you'll need the Auth one.
As you want the function to have access to some Auth functions.

unborn goblet
#

Okay well only Auth ?

rich socket
#

Seems like it, yes.

unborn goblet
#

Probably a stupid question but there is a way to try locally the function ? I guess I dont have to deploy the function each time right ?

rich socket
#

What I'm doing is creating a file named local-server and run it each time with mocked variables, etc.

unborn goblet
#

Well something like that should work (for the function who add the default Team for new user) ?

module.exports = async function (req, res) {
  const client = new sdk.Client();
  const teams = new sdk.Teams(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 teamId = 'APPWRITE_FUNCTION_TEAM_ID';
  const user = JSON.parse(req.variables["APPWRITE_FUNCTION_EVENT_DATA"]);

  try {
    await teams.createTeamMember(teamId, user.$id, ['MEMBER']);
    res.json({ success: `User ${userId} added to the team successfully` });
  } catch (error) {
    console.error('Error adding user to the team:', error);
    res.json({ error: 'Error adding user to the team' });
  }
};
#

But do I have to add the MEMBER rôle ? Or I can leave blank ?

rich socket
#

I think the function name is createMembership instead of createTeamMember, like so:

const r = await teams.createMembership(teamID, email, [], 'url');
rich socket
unborn goblet
# rich socket You can leave it empty

If I got that :

await teams.createMembership(teamId, user.$id, [], 'url');

How Appwrite gonna know if user.$id its an email or an id ? How can I gave him the two like that :

await teams.createMembership(teamId, user.email, user.$id, [], 'url');
rich socket
#

Oh, you're right
You'll need to use the email
But you have it

#

So just like this

await teams.createMembership(teamId, user.email, [], 'url');
unborn goblet
#

but I have to add the id no ?

rich socket
#

No..

#

I know it sounds a bit confusing but it works that way

unborn goblet
#

Appwrite gonna make the link between email and the corresponding user id ?

rich socket
#

Yes

unborn goblet
#

But I can add the user id anyway no (to be sure ahah) ?

rich socket
#

This is the function declaration.

createMembership(teamId: string, email: string, roles: string[], url: string, name?: string):
#

You don't even have the userId field over there.

unborn goblet
#

okay strange. So Im gonna try without

#

There is a way to delete a function with APpwrite CLI ?

rich socket
#

delete from the console?

unborn goblet
#

I delete a function directly from the web ui of Appwrite but still on my console (on my laptop)

unborn goblet
#

ohh appwrite.json

rich socket
#

But you mean that is still in your console

#

After you have deleted it?

unborn goblet
#

I delete on the APpwrite Web UI. So the solution its go to appwrite.json and delete manually the section of the function

rich socket
#

Okay

rich socket
# unborn goblet Yup

In the folder of your appwrite.json run

appwrite functions delete --functionId FUNCTION_ID
unborn goblet
#

ohh that what I was looking for

#

Now I add the user verified function so I just have to add the 'verified' role right ? Like this

module.exports = async function (req, res) {
  const client = new sdk.Client();
  const teams = new sdk.Teams(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 teamId = req.variables["APPWRITE_FUNCTION_TEAM_ID"];
  const user = JSON.parse(req.variables["APPWRITE_FUNCTION_EVENT_DATA"]);

  if (!user.emailVerification) {
    try {
      await teams.createMembership(teamId, user.email, ['verified'], 'url');
      res.json({ success: `User ${user.name} added to the Verified Role successfully` });
    } catch (error) {
      console.error('Error adding user to the role:', error);
      res.json({ error: 'Error adding user to the role' });
    }
  }
};
#

Something wrong. When I add this update event :
users.*.verifications.*.update
I got that :

rich socket
#

Set events like so

  "events" : [
    "users.*.verifications.*.update"
  ]
#

The users.*.verification.*.update returns a Token Object https://appwrite.io/docs/models/token so you need to get the user other way.
Also, you'll need to get the current user membershipId.
And you'll need to use the updateMembershipRoles function.

So in this function you'll need to something like this.

module.exports = async function(req, res) {
  const client = new sdk.Client();
  const teams  = new sdk.Teams(client);
  const users  = new sdk.Users(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 teamId = req.variables['APPWRITE_FUNCTION_TEAM_ID'];

  // Getting Token
  const token = JSON.parse(req.variables['APPWRITE_FUNCTION_EVENT_DATA']);
  // Getting user
  const user  = await users.get(token.userId);

  if (user.emailVerification) {
    try {
      // Getting membership
      const members = teams.listMemberships(teamId, [
        Query.equal('userId', user.$id)
      ]);

      // We have members? we can have only one as we are searching by user ID.
      if (members.total === 1) {
        await teams.updateMembershipRoles(teamId, members.memberships[0].$id, ['verified'], 'url');
        res.json({ success: `User ${user.name} added to the Verified Role successfully` });
      } else {
        throw 'Error looking for a membership user.';
      }

      
    } catch (error) {
      console.error('Error adding user to the role:', error);
      res.json({ error: 'Error adding user to the role' });
    }
  }
};
unborn goblet
rich socket
#

Try to set it in the appwrite.json file, inside the events property, and depoly it

unborn goblet
#

I got same error in console when appwrite deploy function :
Invalid events: Value must a valid array and Event is not valid.

rich socket
#

Can you share the function events part?

{

            "runtime": "node-16.0",
            "path": "functions/sendWelcomeEmail",
            "entrypoint": "src/index.js",
            "ignore": [
                "node_modules",
                ".npm"
            ],
            "execute": [],
            "events": [
            ],
            "schedule": "",
            "timeout": 15
        },
unborn goblet
# rich socket Can you share the function events part? ```json { "runtime": "node-...
{
            "$id": "648c8c94bb9519a5a931",
            "name": "user_verified",
            "runtime": "node-16.0",
            "path": "functions/user_verified",
            "entrypoint": "src/index.js",
            "ignore": [
                "node_modules",
                ".npm"
            ],
            "execute": [],
            "events": [
                "users.*.verifications.*.update"
            ],
            "schedule": "",
            "timeout": 15
        },
        {
            "$id": "648c8cc7c167b6743da6",
            "name": "user_created",
            "runtime": "node-16.0",
            "path": "functions/user_created",
            "entrypoint": "src/index.js",
            "ignore": [
                "node_modules",
                ".npm"
            ],
            "execute": [],
            "events": [
                "users.*.create"
            ],
            "schedule": "",
            "timeout": 15
        }

But its working for user_created

rich socket
#

I think maybe because it should be users.*.verification.*.update in single

unborn goblet
rich socket
#

without the s

unborn goblet
#

If I try to manually verify an account (with Web UI) like that. Do the function gonna be launched ?

#

BEcause there is no execution

rich socket
#

I'm not sure

#

But looks like it should

#

Have you gave it a try?

#

Sorry,

#

I see that it won't propagate any events, as this will use the Users SDK.

unborn goblet
#

Okay Im gonna chck that. For the function 'user_created', she's executed but there is a problem with this line :
await teams.createMembership(teamId, user.email, [], 'url');
Because ive got this error :
Error adding user to the team

rich socket
#

Change to this, so we can get the full error

  } catch (error) {
    console.error(error);
    console.error('Error adding user to the team:');
    res.json({ error: 'Error adding user to the team' });
  }
#

Maybe the user is already in the team.

unborn goblet
#

well my appwrite instance crash ahah idk why

rich socket
#

Oh, is not accessible?

unborn goblet
rich socket
#

Mmmm
Maybe your Docker doesn't start automatically

#

Run

docker compose ls
#

And share the results

unborn goblet
#

ive run docker container ls -a

#

Now i try to restart all container

#

During restarting ive got this error :

Error response from daemon: Cannot restart container eebd9cccf2b8: driver failed programming external connectivity on endpoint appwrite-traefik (9e3dfc5d02a57100f1cbc18dc26012d2dc17b097aa993a6fe69678a91eea8317): Bind for 0.0.0.0:443 failed: port is already allocated
#

And the docker compose ls command :

root@localhost:~# docker compose ls
NAME                STATUS              CONFIG FILES
appwrite            running(18)         /usr/src/code/appwrite/docker-compose.yml
rich socket
#

Maybe you have Nginx/Apache on the server the uses port 443?

#

Because port 443 is in-use then traefik cannot start.

unborn goblet
rich socket
#

Run this, what you get?

ss -tulpn | grep :443
unborn goblet
#

But no container use thze 443 port

rich socket
#

Can you try to restart docker?

service docker restart
unborn goblet
rich socket
#

Happily

unborn goblet
#

btw when Appwrite crash, my function crash too

rich socket
#

That make sense

#

Btw what are the specs for the server?

unborn goblet
# rich socket Btw what are the specs for the server?

I just wanted some advice. I saw that APpwrite offered a Cloud option in Beta, which may be easier. For now I have a VPS with these specs (Ive take the minimum for the development):
CPU :1 vCore
RAM :0.5 Go
SSD :10 Go

#

Idk what do I need for my app

rich socket
#

I'm afraid that the 512mb of RAM will hold your Appwrite back, specially when running functions.
Appwrite itself recommend having at least 2GB or RAM, https://appwrite.io/docs/self-hosting
I my self, got really good results with a 1 vcpu 1 gm ram 25 ssd, so maybe this could be a good start for your project.

P.s. at https://www.hetzner.com/cloud you can get really good servers for less the most providers.

And, in many use-cases Appwrite cloud will be the best solution.

unborn goblet
#

I mean specs for each isntance

#

Like that ?

rich socket
#

Appwrite cloud uses Docker Swarm (on DigitalOcean) for their stack deployment,
This means that there's no way to know, and even more it's irrelevant, as in Docker Swarm the power is shared among the server in the load balancers.

unborn goblet
#

Okay I just ask because I dont know the good way to launch an app ahah (im student) so if paying a VPS is the best option, Im gonna take a vps

rich socket
#

Do you have estimation of your monthly user and usages?

#

Gotcha

#

I would recommend you start with CX11 - intel

unborn goblet
rich socket
#

So start with the basic Intel one,

#

And you can grow from there

unborn goblet
rich socket
#

If you're using only docker compose then you can go with arm64

#

Sometime when wanting to expand it can get difficult.

unborn goblet
rich socket
#

I don't anything on mind right now,

#

For example

#

If you want to integrate some software on the server that has only x64

unborn goblet
#

Well this is the first time I've developed an app, I don't necessarily know the possible improvements. But I would tend to say to have only one server for appwrite. And if I need other software or application, I would rent another server, right?

#

Right now the arm server are way more cheaper than the x86

rich socket
unborn goblet
#

There is estimation price of Appwrite Cloud ? Because if is cheaper or evne little expensive, maybe is the best because power adapts to consumption, right?

rich socket
#

Check this: #🌩│cloud message

unborn goblet
#

Im gonna check that ty

#

Well about my user_created function, ive made a stupid error :

{"error":{"code":400,"type":"general_argument_invalid","response":{"message":"Invalid url: URL host must be one of: localhost, appwrite.nvlab.fr, *.vercel.app","code":400,"type":"general_argument_invalid","version":"1.2.0"}}}
#

Which url do I have to add :
await teams.createMembership(teamId, user.email, [], 'url');
I dont really understand why an url is needed

rich socket
#
 await teams.createMembership(teamId, user.email, [], 'appwrite.nvlab.fr');
unborn goblet
#

Weird, ive got the same error :

{"error":{"code":400,"type":"general_argument_invalid","response":{"message":"Invalid url: URL host must be one of: localhost, appwrite.nvlab.fr, *.vercel.app","code":400,"type":"general_argument_invalid","version":"1.2.0"}}}

BUt i have this code

try {
    await teams.createMembership(teamId, user.email, [], 'appwrite.nvlab.fr');
    res.json({ success: `User ${user.name} added to the team successfully` });
  } catch (error) {
    console.error('Error adding user to the team:', error);
    res.json({ error: 'Error adding user to the team', error: error});
  }
rich socket
rich socket
unborn goblet
#

ohh i find !

#

we have to add 'https://'

#

like that

try {
    await teams.createMembership(teamId, user.email, [], 'https://appwrite.nvlab.fr');
    res.json({ success: `User ${user.name} added to the team successfully` });
  } catch (error) {
    console.error('Error adding user to the team:', error);
    res.json({ error: 'Error adding user to the team', error: error});
  }
rich socket
#

Great,

#

My bad 🤦‍♂️

unborn goblet
#

well the function user_created work !

#

now i have to see if the verified one work too

rich socket
#

Cool

unborn goblet
#

I have to find a way to launch the users..verification..update event

rich socket
#

Mmm, meaning to do trigger it manually?

unborn goblet
#

Because idk yet how add an email verification with smtp provider etc...

rich socket
#

And I assume you didn't set SMTP, so you can fully test it?

unborn goblet
#

Besides, what the best option for email sending ? Sendgrid ?

rich socket
#

Bravo gives 300/Free/Daily

#

So either you can configure one of those options.

#

Or
You'll need to do it manually like so:
Create Another function, make it trigger on users.*.verification.*.create, this will run when a verification token is created. log the token.

Using this method https://appwrite.io/docs/client/account?sdk=web-default#accountCreateVerification
Create the verification token.

Now, use the token you have logged and use the 2-step of the verification process https://appwrite.io/docs/client/account?sdk=web-default#accountUpdateVerification
Like so

await account.updateVerification('[USER_ID]', '[SECRET]');

Remember that you'll need to login the user before running any one of those two function.

Now you will trigger the users.*.verification.*.update