How to capture user at INITIAL login via hooks?

We have manual approval for members (using Ascend built-in approval buttons, whose “click” I cannot capture, I believe). In order to request membership, users have to provide information that is stored in a “form submission” collection. After being approved, we want to transfer this user record set to a separate read/write collection, where the then member can then read and update his/her data via his/her privateMember area (adding a private member page linked to that dataset). For this, we want to capture his first-time-login and then get the record via his email address.

Questions:

  1. I have difficulties to find the right combination of hooks (privateMembersData collection) and available fields (same collection: created (date), last login (date) - which would both be filled at initial login, so going via a query field.value = null would probably not return anything) that would work, so that the function is not fired everytime some function needs to get the user ID? Any suggestion, PLEASE?
  2. Is it the right way to call a .js-hook function from a .jsw-module ? Or is that the wrong approach?

Hey Thomas

If i understand your intention correct. You are simply trying to give the users ability to update their member information.
If you have already added a members area be aware there exist a page called “profile” where a user can see and update their information. You have to be logged in, and the page is handled fully by the members area application meaning no custom coding required.

If you for some reason want to modify that page to a custom look, what you want to do it use the UpdateUserFields API which need to be run in the backend for security.
https://www.wix.com/corvid/reference/wix-users-backend.html#updateUserFields

This allow you to update the data a user have typed in like their name or phone number etc. So make a bunch of inputfields. a button which when clicked collect the data and the logged in userID and call a backend script which updates that user.

Its a common misunderstanding you are not able to add more fields to a users data on wix. Be aware you can if you want to add their address. favorite friend, or if they type with left or right hand, as long as the custom information is in the form of “String”, “number”, “Date”. And by using the actual user API it updates the users in the wix enviorment rather than a custom collection you made. So if you want a triggered email to be sent. its a lot easier to get a users updated mail.

hope this helps

best regards
Claes

Thanks for that, Claes!

The issue is a bit different, I believe (or not? :-)): Corvid does not allow to update an _owner field of a record set after an item has been created, except by using hooks. When a visitor fills in a form, he does not have yet a member ID, so the _owner is just left blank in the form submission collection. Once he is approved (manually, via an Ascend built-in button, which I cannot capture), I need to allocate the then created member ID to the previous “form submission” collection. In fact, I want to take the member record out of that “for every visitor: write-only” collection and transfer it to another one with more selective rights (create: admin, read: admin, update: member, delete: admin). But I only want to do this once - when the user logs in the first time as a member.

As PrivateMembersData hooks only allow for hooks related to get, query, find, but not for before or after insert, the idea was to create a boolean field “hasLoggedIn” in the form submission table, set to false, and then set it to true at the first login of the user.

Every time a user logs in, I would use currentUser.getEmail in PrivateMembersData to query that “for everybody” form submission collection in the backend, in order to see if the “hasLoggedIn” setting is set to true. If it is still set to false, then I would take that user item and transfer it to the more restricted collection,. As at this time he is logged in, the _owner ID would be automatically inserted in that collection.

With this _owner ID being set, I could use a custom page I created in the private member section, so that the user can then update there his private data.

Does that make sense? Or is there a faster way to glory?

I appreciate your support, Claes!!

Oh, sorry, I forgot to add: I do not want the data get dumped in Wix CRM …

Or will the updateProfile API approach insert fields and data directly in the PrivateMembersData collection and is readily accessible for Admin, queries, finds etc.?

Hey again Thomas
So from what im understanding, you want information to be saved which is directly correlated with the user like their “workplace” which you might as well do directly in the privateMemberdata.
The privateMemberData is readable like any other collection (though to get it implemented in editor you have to add members area but you can ignore that if you do not want to use the pages) but can only be updated from backend because it example contain user sensitive data and the ID which is OwnerID. Preventing people like me to force update another persons email address to become mine from client side.

Look into the API i sent you. If there for some reason is something that MUST be made in another collection before the user is logged in. I suggest you consider if it would not be smarter to not collect data for users you have not yet approved. And rather as approval give them the abillity to add information.

Best regards
Claes

Thanks, Claes.

Re the business process: unfortunately, it is a pre-requisite to first collect additional data, then register() the client with a “pending” status and then approve the client as a member manually. We have had a lot of issues with Wix CRM (registering additional addresses in the ContactInfo object, just containing the country of the server somebody was using, when logging in, non-accesible fields in customized registration forms etc.), doubts about the handling by the platform, etc., so we decided to take another route: create a separate data collection and just use ContactInfo for some essentials. It is, what it is …

If you want to see the registration process “in practice” (it’s still not migrated to our live (premium) domain, but the process works), you can click on the lock on the right upper part of the site and go through the registration process (sorry, all in German …): https://jochenimhoff.wixsite.com/test-bwi - we are a pro-bono wine shop with a very special operating model, and none of us involved gets a cent for what we are (happily!) doing. My reward is getting a wramp-up in Javascript for a month already now - from zero to … hell, for the moment being. :slight_smile:

What works until now:

  1. Form submission to write-only collection A (Corvid registration form)
  2. Register() the client, add submitted data incl. members’ owner-ID to write-only collection (so collection A _owner and PrivateMembersData _id match) & manual approval process
  3. creation of a separate collection B (equal in structure to A) with the following rights: create: admin, read: admin, update: member, delete:admin; re data transfer see below
  4. creation of a separate members page containing those data -
    What I still need to do / does NOT work yet:
  5. uploading data to the separate members page mentioned in 4) - only in case the logged in Admin happens to have the array(0) position in the relevant collection A; so it works technically, but not from a roles/rights perspective
  6. at first log-in of a user transfer the record from the write-only collection A to its clone B (with the above rights): I call the function updateItem() on login at site level:
// site level code:
import wixUsers from 'wix-users';   
import {updateItem} from "backend/data"; 

// if logged in, show user elements and hide lock

$w.onReady(() => {          
    wixUsers.onLogin( (user) => { 
        showUserButtons()
        updateItem()
    }); 
if (wixUsers.currentUser.loggedIn) {
    showUserButtons()
}

This backend function updateItem() below does NOT work yet, where I try to …

  1. first check, using the logged-in user, if email is existing in custom collection A (“collection”) AND if the field value for “hasLoggedIn” is SET to false (which would mean he just got approved and never logged in before) - in any other case, leave it there, as the member had already logged in beforehand

  2. if the user is a first-time-log-inner, update the found user data array (item) by first setting the “hasLoggedIn” boolean to true in A (“collection”) (so next time he won’t be a query hit), and get the entire item (client record) from that collection over to B (“target”)

  3. check, just in case, if by some manual intervention somebody had already messed up the restricted database B (“target”) by inserting the same client already; else (what should be the normal case), take “item” from A and insert it in B

COULD YOU PLEASE HAVE A LOOK? It does not work …
Remark: the different ways “email” is written is on purpose - the email field key in the custom collection is set to “eMail”, so don’t worry about that.

// CODE UPDATED ON 24.07.2020 / 18:29CET!!
import wixData from 'wix-data';
import wixUsersBackend from 'wix-users-backend';


export async function updateItem() { //updates Kundenadressen collection with field showing that user has already logged in
let collection = "Kundenadressen"
let target = "KundenPrivat"
let options = {
 "suppressAuth": true,
 "suppressHooks": true};
let user = wixUsersBackend.currentUser;

let isLoggedIn = await user.loggedIn; // bool
const email = await user.getEmail(wixUsersBackend,user.id,options) // use this for queries!!
console.log("user email: " +email)

if (email.length >0){
  wixData.query(collection)
  .eq("eMail", email)
  .eq("hasLoggedIn", false)
  .find(options)
    .then( (results)  => {
 if(results.items.length > 0) {
 let item = results.items[0];
        wixData.get(collection, item,options)
          .then( () => {
          item.hasLoggedIn = true; 
        wixData.update(collection, item,options) // updated boolean field in "Kundenadressen" (collection)
            .then( () => { // start process regarding collection "KundenPrivat" (target)
              wixData.query(target) //queries KundenPrivat collection, if user already existing
                .eq("eMail", email)
                .find(options)
              .then( (conclusion) => {
                console.log("item in KundenPrivat: " +conclusion)
 if(conclusion.items.length === 0) {
                  wixData.insert(target, item,options); //"item" is the item from Kundenadressen (form submission collection) inserted into "KundenPrivat"
                } 
              })
            })
        })
      } else {
 // handle case where no matching items found
              }
            } )
      .catch( (err) => {
 let errorMsg = err;
      } );
}} 


Well, it does not work. I does not update A, and it does not transfer the record from A to B, although I have suppressed authorities and hooks
See below for the code, please.

  1. And I will still need to connect the private member page to that collection B …
    and hope that it will finally work on that PrivateMembers area page …

My main issue is the async logic of code. And avoiding repetitive steps …

Oh, just in case you really try out the process - field validation in the input form has been taken out for the moment being, so you can just insert an email, CONFIRM IT in the input field afterwards, insert first and last names, plus a password, to shorten things.

Thanks anyway, even if you do not find the time for this, Claes! Formulating my issues already help :-=)

@clsnlsen
CODING ISSUE SOLVED - PROCESS WORKING FINE FOR ADMIN USER;
USER RIGHTS QUESTION REMAINING

Hi Claes,

I solved the coding part (see below for the code working fine now), but there is a user rights issue still, as it works only in the editor view, but not in live mode, if the user has no admin rights.

I passed “options” supprAuth etc., but this is apparently not enough, as I am calling the function contained in a backend .jsw-module from the front-end, at log-in.

Everything related to the “source” collection (form submission type) works fine, including backend update. But it does not insert the record into the “target” collection (create: admin, read: admin, update: member (author), delete: admin) supprAuth does not overwrite the users rights. But setting “create” to everybody did not help either, nor setting update to “member” (not author).

It’s about this piece in the code - it does not INSERT the record in the collection (it does in the editor mode).

               .then( () => {
                  wixData.query(target,options) 
                    .eq("_id", item._id)
                    .find(options)
                    .then( (conclusion) => {
 if(conclusion.items.length === 0) {
                      wixData.insert(target,item,options);
                      } 
                    })

I probably will have to link the code to a hook “before insertion” regarding the “target” collection in a backend .js file, do I? But I have no clue, which hook to take … and how to adapt the below code to such a hook .js - and when to call it, and from where.

Could you give advice, please?
Thanks in advance & best regards,
Thomas

For the sake of completeness, see the complete code hereafter. Probably not elegant … but as long as it is stable. …

import wixData from 'wix-data';
import wixUsersBackend from 'wix-users-backend';


export async function updateItem() {
let source = "ABC" 
let target = "XYZ" 
let item = []
let options = {
 "suppressAuth": true,
 "suppressHooks": true}; 
let user = wixUsersBackend.currentUser;
let isLoggedIn = await user.loggedIn;
const email = await user.getEmail(wixUsersBackend,user.id,options)
 if (email.length >0){
    wixData.query(source,options) 
      .eq("eMail", email)
      .find(options)
        .then( (results)  => { 
 if(results.items.length > 0) {
            item =  results.items[0];
 let firstLogin = item.hasLoggedIn
 let hit = item._id 
 if (firstLogin === false) {
                  wixData.get(source, hit,options)
                    .then( () => {
                      item.hasLoggedIn = true;
                      wixData.update(source,item,options) 
 return item
                } )
                .then( () => { 
                  wixData.query(target,options) 
                    .eq("_id", item._id)
                    .find(options)
                    .then( (conclusion) => {
 if(conclusion.items.length === 0) {
                      wixData.insert(target,item,options);
                      } 
                    })
                       })
          } else {
          console.log("user boolean already set to true") 
          }
  } else {
  console.log("ERROR - user has logged in, but no record found!")
  }
            } )              
      .catch( (err) => {
 let errorMsg = err;
      } );
}}