Can “current user” ever be empty? If so, how?
I don’t think so… is there a use case where you need it to be empty?
Right the opposite, I’m using that “yes/no:formated as text” hack to form a better text expression and the condition I use is “current user is not empty” because I assumed it won’t ever be.
It can be for API workflow. If a user is interacting with the app, then no.
See Introduction - Bubble Docs
Current user
This represents the current user using the app. The user can either be logged in, in which case you have access to their email, etc., or logged out. If the user is logged out, you can still modify the user object, but once the user closes their browser, you will not be able to access the user’s information.
@vini_brito, I use current date/time for the hack. Once that is empty we are all in trouble!
@Kfawcett, I wanted to say that you are correct. And I was about to write that… And then I decided to test it. (BTW, the documentation you pointed to is not actually helpful around this point. From my reading of it, it’s just a wonky description of what Current User is… and one that I don’t feel particularly helps new users, unfortunately.)
But it turns out that Current User is never empty – even in an API Workflow. This is counter-intuitive… because if we go into the Data tab and create a thing, we find that thing’s Created By is null…
And so, we might assume that, if we run an API Workflow in the superuser context (i.e., we “ignore privacy rules when running workflow”), that this means that Current User will resolve to this null and that this “null User” represents the system/superuser.
Surprisingly, this is not the case.
Let’s explore that in a second. But first: Note that there are quite a few page-level “always available” attributes that we can use to do the “trick” of turning a boolean into a text and thereby get access to the long text input fields that @vini_brito and @anthony and myself will sometimes take advantage of.
Current Date/Time is just one of these. It’s the one that I mentioned in my original explanation to @anthony about how you do this “trick” (which is not a trick or a hack BTW, it’s just what you have to do – it’s completely valid as a technique and doesn’t break any rules or take advantage of some unplugged hole or something, FYI).
I used Current Date/Time in my original example about this as it’s (1) the first one that came to mind and (2) it’s easiest to remember. ALSO, (3) it is a property we can evaluate in both on-page (client-side) and API Workflows (server-side). It’s always available and, logically, it is never empty (and, empirically, this turns out to be true as well).
But there are other on-page properties we could use in on-page workflows. “Current User is not empty
” is in fact one of them – it is never empty client-side (and, though it’s surprising, it seems that is never empty server-side) . Let’s consider some other things we can evaluate to do the long text field trick as an alternative:
-
This url is not empty
. This may be superior toCurrent Date/Time is empty
as (1) it’s a text and it turns out that it is significantly faster to evaluate the “emptiness” of a text than it is to evaluate the "emptiness’ of a date [this seems strange, but I mention how I came to discover this here], and (2) when we reference these things, we are in fact asking Bubble to evaluate them and so some function gets run. Getting “this url” is (most likely) just referencing window.location.href. Getting Current Date/Time is probably accomplished by doing new Date(). It’s almost a foregone conclusion that the former is faster than the latter. But, again, this value (“This url”) is not available to us in API Workflow (which makes sense, of course, as we would assume that there is no page/URL context inside of a server-side workflow). -
Website home URL is not empty
. Website home URL is similar to “This URL” mentioned above. But it’s also available to API Workflows. Interesting, right? In the page, this may be just a reference to window.location.hostname or something similar. In API Workflows it must be something akin to an environment variable (maybe it’s that way in the page too). Anyway, as a text it has all the advantages of “This url” above and it’s accessible in an API Workflow. Also, it is never empty. So this one is a hot pick for sure, but I think there’s actually a better one… -
This might be the best option. It’s available both in page and in API Workflows. It’s certainly some sort of environment variable. And this probably evaluates the fastest of any other available option. (I have not tested that, but this surmise is reasonable.)Is Development version formatted as text
. “Is Development version” is already a boolean, right? So we don’t need to evaluate if it’s empty, we can just skip right to:formatted as text
. Of course it is true in dev mode and false in live mode. But that’s not a big deal. Just put the same text expression in the yes and no long text fields that you get. Illustration:
I might have mentioned this to @anthony in my original explanation of how to get to the long text fields, but this would have been harder to explain in the context of that original discussion, right? But now that we’re exploring new dimensions of how to approach this technique, we can all understand what’s going on here.
- Honorable mention category: If you only care about doing this trick in the page… Just create a custom state on your page (could be anywhere) of type yes/no. It’ll be false by default. Don’t ever change it. We’re not going to store anything there. We are only going to use it to do this trick. Now
that_custom_state formatted as text
will reveal the long text fields. In this case, put your text expression in the “no” field, because this expression always evaluates to “no” (it’s like the opposite ofCurrent Date/Time is not empty
, ya dig?).
We could go on and on about different candidates and their pros and cons, but the ones listed above are all solid alternatives to Current Date/Time is not empty
.
BTW, if you DO need to do this in both on-page and server-side workflows, here’s a screencap of all of the things we have access to in API Workflows:
BEHAVIOR OF “CURRENT USER” IN API WORKFLOWS
OK. So, now that we’ve covered all of that, what about Current User in the context of API Workflows? Let’s get back to that.
The documentation, and our general sense of how Bubble works, leads us to think about API Workflows this way:
When we schedule an API Workflow, that workflow can run in one of two contexts: It can run in the context of Current User, or it can run in the context of the app itself (as superuser, administrator, God-mode, whatever you want to call it).
In the former case, the workflow will respect privacy rules and stuff like that as if it was being run by Current User (Current User in this case means “the user whose action caused this API Workflow to run”, eh? Current User is passed from the client up to the server level.)
In the latter case, the workflow will ignore privacy rules and can do any freaking thing you ask it to. (Even delete the list of “do a search for… all users”.) Neat, right!? And we might kind of assume that this means that the workflow literally runs in some other context (that the workflow is not associated with the Current User that caused it to be scheduled, but is now a “system” workflow). But we’ll explore that.
So when does an API Workflow run in the user context and when does it run in the scary superuser context? Well, we control that with the “ignore privacy rules” checkbox. Simple enough.
Here’s an example. Let’s create two buttons – one will run our API Workflow in the user context (respecting privacy rules) and the other sill run our API Workflow in superuser (ignore privacy rules) context:
The left one has this workflow on click:
^^^ We’re going to run the API Workflow endpoint “do-something”, but respect privacy rules. This is what we’d think of as running “in the Current User context”.
The right one has this workflow on click:
^^^ We’re going to run the API Workflow endpoint “do-something” with no regard for privacy rules. This is what we’d think of as running “in admin/superuser/God-mode context”.
And now you’re wondering, “OK, what’s in our do-something workflow?” It’s real simple: We’re just going to create a logging object that I’ve called an “Inspektor”. This object will record the unique ID of Current User inside the workflow and tell us (somewhat redundantly) if Current User is empty. So the endpoint is set up like this:
And its single action is set up like this:
So, as you can see, that endpoint will respect privacy rules unless we tell it otherwise. Also, it will just create a new Inspektor object that tells us something about what’s going on inside of the workflow.
Now, let’s run it as the Current User. We do that by clicking the left button (I guess I shoulda done this as a video, eh?). Anyway, we expect that what will happen is that (1) Current User will be me and this object will appear as if indeed it was created by me.
I click the left button. And now I go look in the data tab to see what our Inspektor holds:
^^^ Well, we get exactly what we expect. Current User is me (that’s my unique ID), Current User was not empty [duh, we say] and the Created By for the inspector is me (that’s the email for this account representing me).
NOW, what happens if I click the right button? The God-mode button? Will this workflow still have a Current User context? Or will the Current User in this version not be “me”, but that mysterious null User that we think represents the system? Let’s find out!!!
I click the right button (which - remember - runs “do-something” but has the “ignore privacy rules” checkbox checked). Let’s go look in the Data tab at that new Inspektor:
That result might be bit surprising. Apparently, I ran the workflow and I created the Inspektor. Just like in the first case. We might have thought that the Current User would look like system here. But no, User context is preserved. (However, this workflow could have done things that this User could not normally have done, because of privacy rules.)
OK, so can we EVER get Current User to be empty? I can think of one more way this might happen. Let’s make our do-something endpoint totally unprotected, tell it to ignore privacy rules and hit it as an unidentified user.
Here are our changes to do-something:
And now we hit that with Postman:
^^^^ no auth, no body, no nothin’
This should run as the system/app/God-mode… But what does that LOOK like? Let’s examine this new Inspektor:
WHOA! See what happens there? Current User still has a value! But the Inspektor is created with a null value for the Created By user (just as would happen if we created this thing in the Data tab).
The “unique ID” for the “Current User” assigned to this workflow is “non_authenticated_user_myappname_test”, rather than the usual uuid style unique string.
At this point, I know what you’re thinking: What happens if I hit this with authentication? (I tried it and if you’re using a global style app token (the superuser type ones you can create in Settings), this will be something like “authenticated_user_etc…”. If we send authentication with username and pass or an individual user token, we get the unique ID of that User.)
So there you go: ODDLY, Current User is never empty, even in API Workflows. However, the Current User can have a special value in the case we examine above. If Current User is of this special type (an authenticated or non-authenticated “all privileges” type of “user” hitting an endpoint), objects created by the workflow have a null Created By user (indicating they are created by the system).
(I have not tested Recurring Events here, but perhaps I’ll leave that to someone else. There is no reason to think that the behavior will be different.)
@keith didn’t have time to read everything you wrote, so I may miss something important so forgive me if the below is covered.
It’s been my experience as I was building out webhooks/endpoints for external systems to POST something back to Bubble, then it has no concept of who the user is to update as there is no actual user.
Hi Keith - yeah, I look at what happens when you hit such an endpoint. You’re correct in that – the way you’d typically set this up (like maybe the endpoint does not require authentication OR it takes a global-type app auth token (the kind you create in settings) – the workflow doesn’t have a typical type of User.
However, Current User is not empty. In the unauthenticated case, Current User is not empty and its unique ID is like “non_authenticated_user_myappname_test”. In the authenticated case, Current User is not empty and its unique ID is like “authenticated_user_myappname_test” (clearly, the “test” part is probably “live” in live mode).
There’s also the case of where you pass a username and password to the API (or you do that and retrieve a token and then use that User-specific token). In that case, Current User is the one you would expect – just as if that User were logged in on the client and the unique ID will look like you are used to seeing it!
The thing that happens if we hit a workflow endpoint (and either use an app token or the workflow “ignores privacy rules”), OBJECTS created by the workflow will have a Created By of null. (Just like things the system creates for you when you tell it to from the Data tab.) But Current User has a value and it’s one of those special type ones I describe above.
@Kfawcett, the interesting thing is you can only discover this through direct observation in the way that I did it in the long long explanation.
If we just “infer” what was going on with Current User, we come to the wrong conclusion…
What I mean is, if your test case is: “OK, I’m going to make an API endpoint that creates a thing. I will then examine that thing and see who created it.” … If you do that, you will find:
“Oh, the thing that was created has a null value for Created By.” … and then you will assume:
“Ah, so this means that Current User was null, so it was empty. Therefore, these workflows run in the context of ‘no user’, which is kind of what we would expect.”
But this is an incorrect conclusion. It turns out that inside the workflow, Current User has one of those “special” values. We can see that when we write that value into the Thing that we are creating. When we do that, we reveal the secret names of these special users.
(The real facts of this blew my mind when I saw what happens. It’s very interesting and unexpected. It’s not “wrong”, but it’s not what we would intuit!)
@keith
I’m impressed!
Laughed a few times through the explanation and I thank you for putting it up, that kind of test popped in my mind too and I even had it as a task, since I have a “schedule workflow” that uses “current user” and it seemed to work properly, but I thought “what if it works properly by accident and will eventually fall apart when it shouldn’t?”, that’s why I wanted to test that.
That seems the best one for me too! But what if actually runs a complicated series of functions to analyze hundreds of arrays for intricate variables to detect if it’s in the dev mode?
Just kidding!
Don’t forget to purge database history beforehand!
We’d definitely be! An app crashing would be the smallest of problems…
At the end of the day, the No User, created by any outside API Workflow calls, will be used by Bubble internal server as PST time, affecting time zone for the rest of the same workflow. I already asked as an idea the possibility of selecting between local time zone or others. Thanks @keith for your explanations.