Cloud functions for Morarable part 8

Hey guys
Iโ€™m struggling to get a response in the console from my cloud function. Ill post my code below if anyone is good with cloud functions. Any help is much appreciated.
Cheers

HTML

<!DOCTYPE html>

<html lang="en">

<head>

    <link rel="shortcut icon" href="">

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Morarables</title>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">

    <link rel="stylesheet" href="main.css">

</head>

<script>

  Moralis.init("iyhSgWOnDLaSy73cTGRPT2pQ1yG6TNbwr5pzKsIo"); // app id from moralis

  Moralis.serverURL = "https://5platkya43gg.usemoralis.com:2053/server"; // server URl from moralis

  async function getItems(){

    const userItems = await Moralis.Cloud.run("getUserItems")

    console.log(userItems)

  }

  getUserItems()

</script>

<body class="bg-dark">

    <nav class="navbar navbar-expand-lg navbar-dark bg-transparent border-bottom border-light>

        <div class="container-fluid">

          <a class="navbar-brand" href="#">Morarable</a>

          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">

            <span class="navbar-toggler-icon"></span>

          </button>

          <div class="collapse navbar-collapse" id="navbarNav">

            <ul class="navbar-nav mr-auto">

              <li class="nav-item">

                <a class="nav-link active" aria-current="page" href="#">Home</a>

              </li>

            </ul>

          </div>

        </div>

      </nav>

    <div>

        <button id="btnConnect">Connect Wallet</button>

        <button id="btnUserInfo">Profile</button>

        <button id="btnOpenCreateItem">Create</button>

        <button id="btnMyItems">My Items</button>

    </div>

    <div id="userInfo">

        <h4>User Profile</h4>

        <input type="text" id="txtUsername" required placeholder="Enter username">

        <input type="text" id="txtEmail" placeholder="Enter email">

        <small>Optional</small>

        <img width="50" height="50" src="" id="imgAvatar" alt="">

        <label for="fileAvatar">Select Avatar</label>

        <input type="file" id="fileAvatar">

        <button id="btnLogOut">Log out</button>

        <button id="btnCloseUserInfo">Close</button>

        <button id="btnSaveUserInfo">Save</button>

    </div>

    <div id="createItem">

        <h4>Create Item</h4>

        <input type="text" id="txtCreateItemName" required placeholder="Enter name">

        <textarea id="txtCreateItemDescription" cols="30" rows="5" placeholder="Enter description"></textarea>

        <input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required>

   

        <label for="selectCreateItemStatus">Status</label>

        <select id="selectCreateItemStatus">        

            <option value="0">Not for sale</option>

            <option value="1">Instant buy</option>

            <option value="2">Accept Offers</option>

        </select>

        <label for="fileCreateItemFile">Select File</label>

        <input type="file" id="fileCreateItemFile">

        <button id="btnCloseCreateItem">Close</button>

        <button id="btnCreateItem">Create!</button>

    </div>

    <div id="userItems">

      <h4>My Items</h4>

      <div id="userItemsList"></div>

      <button id="btnCloseUserItems">Close</button>

    </div>

    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

    <script src="https://unpkg.com/moralis@latest/dist/moralis.js"></script>

    <script src="main.js"></script>

    <script src="abi.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>

</body>

</html>

Javascript

const serverUrl = "https://5platkya43gg.usemoralis.com:2053/server";

const appId = "iyhSgWOnDLaSy73cTGRPT2pQ1yG6TNbwr5pzKsIo";

const TOKEN_CONTRACT_ADDRESS = "0x9731268F2f3d39eeaF9925F1D8327c26b0Cd0dA2";

Moralis.start({ serverUrl, appId });

init = async () => {

    hideElement(userItemsSection);

    hideElement(userInfo);

    hideElement(createItemForm);

    await Moralis.enableWeb3();

    window.web3 = new Web3(web3.currentProvider);

    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);

        initUser();

}

initUser = async () => {

    if (await Moralis.User.current()){

        hideElement(userConnectButton);

        showElement(userProfileButton);

        showElement(openCreateItemButton);

        showElement(openUserItemsButton);

    }else{

        showElement(userConnectButton);

        hideElement(userProfileButton);

        hideElement(openCreateItemButton);

        hideElement(createItemForm);

        hideElement(openUserItemsButton);

    }

}

login = async () => {

    try {

        await Moralis.authenticate();

        initUser();

    } catch (error) {

        alert(error)

    }

}

logout = async () => {

    await Moralis.User.logOut();

    hideElement(userInfo);

    initUser();

}

openUserInfo = async () => {

    user = await Moralis.User.current();

    if (user){    

        const email = user.get('email');

        if(email){

            userEmailField.value = email;

        }else{

            userEmailField.value = "";

        }

        userNameField.value = user.get('username');

        const userAvatar = user.get('avatar');

        if(userAvatar){

            userAvatarImg.src = userAvatar.url();

            showElement(userAvatarImg);

        }else{

            hideElement(userAvatarImg);

        }

        showElement(userInfo);

    }else{

        login();

    }

}

saveUserInfo = async () => {

    user.set('email', userEmailField.value);

    user.set('username', userNameField.value);

    if (userAvatarFile.files.length > 0) {

        const avatar = new Moralis.File("avatar1.jpg", userAvatarFile.files[0]);

        user.set('avatar', avatar);

    }

    await user.save();

    alert("User info saved successfully!");

    openUserInfo();

}

createItem = async () => {

    if (createItemFile.files.length == 0){

        alert("Please select a file!");

        return;

    } else if (createItemNameField.value.length == 0){

        alert("Please give the item a name!");

        return;

    }

const nftFile = new Moralis.File("nftFile.jpg",createItemFile.files[0]);

await nftFile.saveIPFS();

const nftFilePath = nftFile.ipfs();

const nftFileHash = nftFile.hash();

const metadata = {

    name: createItemNameField.value,

    description: createItemDescriptionField.value,

    image: nftFilePath,

};

const nftFileMetadataFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});

await nftFileMetadataFile.saveIPFS();

const nftFileMetadataFilePath = nftFileMetadataFile.ipfs();

const nftFileMetadataFileHash = nftFileMetadataFile.hash();

const nftId = await mintNFT(nftFileMetadataFilePath);

const Item = Moralis.Object.extend("Item");

const item = new Item();

item.set('name', createItemNameField.value);

item.set('description', createItemDescriptionField.value);

item.set('nftFilePath', nftFilePath);

item.set('nftFileHash', nftFileHash);

item.set('metadataFilePath', nftFileMetadataFilePath);

item.set('metadataFileHash', nftFileMetadataFileHash);

item.set('nftId', nftId);

item.set('nftContractAddress', TOKEN_CONTRACT_ADDRESS);

await item.save();

console.log(item);

}

mintNFT = async (metadataUrl) => {

    const receipt = await tokenContract.methods.createItem(metadataUrl).send({from: ethereum.selectedAddress});;

    console.log(receipt);

    return receipt.events.Transfer.returnValues.tokenId;

}

hideElement = (element) => element.style.display = "none";

showElement = (element) => element.style.display = "block";

openUserItems = async () => {

    user = await Moralis.User.current();

    if (user){    

        showElement(userItemsSection);

    }else{

        login();

    }

}

//Navbar

const userConnectButton = document.getElementById("btnConnect");

userConnectButton.onclick = login;

const userProfileButton = document.getElementById("btnUserInfo");

userProfileButton.onclick = openUserInfo;

//Userinfo

const userInfo = document.getElementById("userInfo");

const userNameField = document.getElementById("txtUsername");

const userEmailField = document.getElementById("txtEmail");

const userAvatarImg = document.getElementById("imgAvatar");

const userAvatarFile = document.getElementById("fileAvatar");

document.getElementById("btnCloseUserInfo").onclick = () => hideElement(userInfo);

document.getElementById("btnLogOut").onclick = logout;

document.getElementById("btnSaveUserInfo").onclick = saveUserInfo;

//Item Creation

const createItemForm = document.getElementById("createItem");

const createItemNameField = document.getElementById("txtCreateItemName");

const createItemDescriptionField = document.getElementById("txtCreateItemDescription");

const createItemPriceField = document.getElementById("numCreateItemPrice");

const createItemStatusField = document.getElementById("selectCreateItemStatus");

const createItemFile = document.getElementById("fileCreateItemFile");

const openCreateItemButton = document.getElementById("btnOpenCreateItem");

openCreateItemButton.onclick = () => showElement(createItemForm);

document.getElementById("btnCloseCreateItem").onclick = () => hideElement(createItemForm);

document.getElementById("btnCreateItem").onclick = createItem;

//User Items

const userItemsSection = document.getElementById("userItems");

const userItems = document.getElementById("userItemsList");

document.getElementById("btnCloseUserItems").onclick = () => hideElement("userItemsSection");

const openUserItemsButton = document.getElementById("btnMyItems");

openUserItemsButton.onclick = openUserItems;

init();

abi.js

var tokenContractAbi =

[

    {

      "inputs": [],

      "stateMutability": "nonpayable",

      "type": "constructor"

    },

    {

      "anonymous": false,

      "inputs": [

        {

          "indexed": true,

          "internalType": "address",

          "name": "owner",

          "type": "address"

        },

        {

          "indexed": true,

          "internalType": "address",

          "name": "approved",

          "type": "address"

        },

        {

          "indexed": true,

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "Approval",

      "type": "event"

    },

    {

      "anonymous": false,

      "inputs": [

        {

          "indexed": true,

          "internalType": "address",

          "name": "owner",

          "type": "address"

        },

        {

          "indexed": true,

          "internalType": "address",

          "name": "operator",

          "type": "address"

        },

        {

          "indexed": false,

          "internalType": "bool",

          "name": "approved",

          "type": "bool"

        }

      ],

      "name": "ApprovalForAll",

      "type": "event"

    },

    {

      "anonymous": false,

      "inputs": [

        {

          "indexed": true,

          "internalType": "address",

          "name": "from",

          "type": "address"

        },

        {

          "indexed": true,

          "internalType": "address",

          "name": "to",

          "type": "address"

        },

        {

          "indexed": true,

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "Transfer",

      "type": "event"

    },

    {

      "inputs": [

        {

          "internalType": "uint256",

          "name": "",

          "type": "uint256"

        }

      ],

      "name": "Items",

      "outputs": [

        {

          "internalType": "uint256",

          "name": "id",

          "type": "uint256"

        },

        {

          "internalType": "address",

          "name": "creator",

          "type": "address"

        },

        {

          "internalType": "string",

          "name": "uri",

          "type": "string"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "to",

          "type": "address"

        },

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "approve",

      "outputs": [],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "owner",

          "type": "address"

        }

      ],

      "name": "balanceOf",

      "outputs": [

        {

          "internalType": "uint256",

          "name": "",

          "type": "uint256"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "getApproved",

      "outputs": [

        {

          "internalType": "address",

          "name": "",

          "type": "address"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "owner",

          "type": "address"

        },

        {

          "internalType": "address",

          "name": "operator",

          "type": "address"

        }

      ],

      "name": "isApprovedForAll",

      "outputs": [

        {

          "internalType": "bool",

          "name": "",

          "type": "bool"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [],

      "name": "name",

      "outputs": [

        {

          "internalType": "string",

          "name": "",

          "type": "string"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "ownerOf",

      "outputs": [

        {

          "internalType": "address",

          "name": "",

          "type": "address"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "from",

          "type": "address"

        },

        {

          "internalType": "address",

          "name": "to",

          "type": "address"

        },

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "safeTransferFrom",

      "outputs": [],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "from",

          "type": "address"

        },

        {

          "internalType": "address",

          "name": "to",

          "type": "address"

        },

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        },

        {

          "internalType": "bytes",

          "name": "data",

          "type": "bytes"

        }

      ],

      "name": "safeTransferFrom",

      "outputs": [],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "operator",

          "type": "address"

        },

        {

          "internalType": "bool",

          "name": "approved",

          "type": "bool"

        }

      ],

      "name": "setApprovalForAll",

      "outputs": [],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "bytes4",

          "name": "interfaceId",

          "type": "bytes4"

        }

      ],

      "name": "supportsInterface",

      "outputs": [

        {

          "internalType": "bool",

          "name": "",

          "type": "bool"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [],

      "name": "symbol",

      "outputs": [

        {

          "internalType": "string",

          "name": "",

          "type": "string"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    },

    {

      "inputs": [

        {

          "internalType": "address",

          "name": "from",

          "type": "address"

        },

        {

          "internalType": "address",

          "name": "to",

          "type": "address"

        },

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "transferFrom",

      "outputs": [],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "string",

          "name": "uri",

          "type": "string"

        }

      ],

      "name": "createItem",

      "outputs": [

        {

          "internalType": "uint256",

          "name": "",

          "type": "uint256"

        }

      ],

      "stateMutability": "nonpayable",

      "type": "function"

    },

    {

      "inputs": [

        {

          "internalType": "uint256",

          "name": "tokenId",

          "type": "uint256"

        }

      ],

      "name": "tokenURI",

      "outputs": [

        {

          "internalType": "string",

          "name": "",

          "type": "string"

        }

      ],

      "stateMutability": "view",

      "type": "function",

      "constant": true

    }

  ]

Cloud function

Moralis.Cloud.define("getUserItems", async (request) => {
  
  const query = new Moralis.Query("EthNFTTokenOwners");
  query.equalTo("contract_type", "ERC721");
  query.containedIn("owner_of", request.user.attributes.accounts);
  const queryresults = await query.find();
  
  let sum = 0;
  for(let i = 0; i < results.length; ++i) {
    results.push({
        "tokenObjectId": queryResults[i].id,
        "tokenId": queryResults[i].attributes.token_id,
        "tokenAddress": queryResults[i].attributes.token_address,
        "symbol": queryResults[i].attributes.symbol,
        "tokenUri": queryResults[i].attributes.token_uri,
      });
    }
    return results;
  });

You can look at the final cloud function code. Your cloud function has some issues e.g. you are trying to loop over results which doesnโ€™t exist.

1 Like

Hi Glad
I fixed up my cloud function with the link above but Iโ€™m still not getting a response to the cloud function in the console.
Cheers :slight_smile:

What does your cloud function look like now?

You can add logger.info (and then check your Moralis server logs) at different parts of the cloud function to find out where something is failing e.g. if queryresults is not finding anything.

Hi Glad
This is my cloud function
Cheers

Cloud

/******/ (() => { // webpackBootstrap
/******/ 	/* webpack/runtime/compat */
/******/ 	
/******/ 	if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
Moralis.Cloud.define("getUserItems", async (request) => {

    const query = new Moralis.Query("NFTTokenOwners");
    query.equalTo("contract_type", "ERC721");
    query.containedIn("owner_of", request.user.attributes.accounts);
    const queryResults = await query.find();
    const results = [];
    for (let i = 0; i < queryResults.length; ++i) {
      results.push({
        "tokenObjectId": queryResults[i].id,
        "tokenId": queryResults[i].attributes.token_id,
        "tokenAddress": queryResults[i].attributes.token_address,
        "symbol": queryResults[i].attributes.symbol,
        "tokenUri": queryResults[i].attributes.token_uri,
      });
    }
    return results;
  });

module.exports = __webpack_exports__;
/******/ })()
;

You will have to use web3api requests to get those owners now. That table is not present any more in latest versions of the server.