Can't figure out how to transfer object access

What I’m trying to do here is have a user create the item then link it to that user but when the user puts it up for sale on the auction portion of the app and someone purchases it then I need to transfer the read and update capabilities to a new user while revoking access to the previous user. Should this be done with roles or ACL? I was trying to follow the Back4app tutorial but I can’t figure out how to adapt it to flutter and how to make it work for my purpose. Another thing is that each object has multiple properties which are stored in separate columns. If anyone has example code that would help out a ton. I have some parts of it coded already but I’m not sure if that code will even be able to be adapted to this purpose or if I’ll have to redo those parts completely.

I believe ACL would be a good way to do that. You can initially set the ACL to the first owner and then update the ACL to the new owner. Could you share the code that you’ve tried so far? It might be easier to help.

Here is the main.js:

Parse.Cloud.define("getTicketsForUser", async(request) => {
    var currentUser = request.user;
    var query = new Parse.Query("Ticket");
    query.equalTo("user", currentUser);
    query.limit(100);
    query.include("user");
    query.find({useMasterKey: true });
    var resultsArray = [];
    for (let i = 0; i < results.length; i++) {
        var ticket = results[i];
        var tempUser = ticket.get("user");
        var jsonUser = tempUser.toJSON();
        delete jsonUser.email;
        delete jsonUser.username;

        jsonUser.__type = "Object";
        jsonUser.className = "_User";

        var cleanedTicket = ticket.toJSON();
        cleanedTicket.user = jsonUser;
        cleanedTicket.__type = "Object";
        cleanedTicket.className = "Ticket";
        resultsArray.push(cleanedTicket);
    }
    return resultsArray;
}


Parse.Cloud.define("linkTicketToUser", async(request) => {
    var currentUser = request.user;
    var ticket = Parse.Object("Ticket").objectId = "eMaeyc5khm";
    ticket.set("user", currentUser);
    ticket.set("userObjectId", currentUser.id);
    ticket.save(null, {
        useMasterKey: true
    });
});

Parse.Cloud.define('setUsersAcls', function (request, response) {
    var currentUser = request.user;
    currentUser.setACL(new Parse.ACL(currentUser));
    currentUser.save(null, {
        useMasterKey: true,
        success: function (object) {
            response.success("Acls Updated");
        },
        error: function (object, error) {
            response.error("Got an error " + error.code + " : " + error.description);
        }
    });
});

One thing to preface this is that the Services and WalletPage classes are both seperate files. Also all the data is supposed to become JSON format via quicktype.io. I’ll link that file in a seperate comment. Here is all the needed flutter to understand what I’m trying to do:

class Services {
  static getTickets() async {
    final ParseCloudFunction getTickets =
        ParseCloudFunction('getTicketsForUser');
    final ParseResponse result = await getTickets.execute();

    if (result.success) {
      List<dynamic> tickets = result.results;
      return tickets;
    }
  }
}
``
class WalletPage extends StatefulWidget {

  @override

  _WalletPageState createState() => _WalletPageState();

}

class _WalletPageState extends State<WalletPage> {

  bool closeTopContainer = false;

  double topContainer = 0;

  List<Widget> itemsData = [];

  List<Ticket> ticketList;

  void getPostsData() {

    List<Ticket> responseList = ticketList;

    List<Widget> listItems = [];

    Ticket ticket;

    responseList.forEach((post) {

      listItems.add(InkWell(

          onTap: () {

            navigateToTicketPage();

          },

          child: Container(

              height: 150,

              margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),

              decoration: BoxDecoration(

                  borderRadius: BorderRadius.all(Radius.circular(20.0)),

                  color: Colors.white,

                  boxShadow: [

                    BoxShadow(

                        color: Colors.black.withAlpha(100), blurRadius: 10.0),

                  ]),

              child: Padding(

                padding:

                    const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),

                child: Row(

                  mainAxisAlignment: MainAxisAlignment.spaceBetween,

                  children: <Widget>[

                    Expanded(

                      child: SwipeDetector(

                        child: Column(

                          crossAxisAlignment: CrossAxisAlignment.start,

                          children: <Widget>[

                            Text(

                              ticket.event,

                              style: const TextStyle(

                                  fontSize: 24, fontWeight: FontWeight.bold),

                            ),

                            Text(

                              ticket.section.toString(),

                              style: const TextStyle(

                                  fontSize: 17, color: Colors.grey),

                            ),

                            Text(

                              ticket.row.toString(),

                              style: const TextStyle(

                                  fontSize: 17, color: Colors.grey),

                            ),

                            Text(

                              ticket.seat,

                              style: const TextStyle(

                                  fontSize: 17, color: Colors.grey),

                            ),

                          ],

                        ),

                        onSwipeRight: () {

                          navigateToSale();

                        },

                      ),

                    ),

                    Image.asset(

                      "assets/images/matchuplogos/cubs.png",

                      //"assets/images/${post["image"]}",

                      height: 100,

                      width: 100,

                    )

                  ],

                ),

              ))));

    });

    setState(() {

      itemsData = listItems;

    });

  }

  @override

  void initState() {

    super.initState();

    Services.getTickets().then((tickets) {

      ticketList = tickets;

    });

    getPostsData();

  }

  void navigateToTicketPage() {

    Navigator.push(

      context,

      MaterialPageRoute(builder: (context) => TicketPage()),

    );

  }

  void navigateToSale() {

    Navigator.push(

      context,

      MaterialPageRoute(builder: (context) => SellingPage()),

    );

  }

  @override

  Widget build(BuildContext context) {

    final Size size = MediaQuery.of(context).size;

    //final double categoryHeight = size.height * 0.30;

    return SafeArea(

      child: Scaffold(

        backgroundColor: Colors.grey[900],

        body: Container(

          height: size.height,

          child: Column(

            children: <Widget>[

              Row(

                children: <Widget>[

                  Text(

                    "  Events",

                    style: TextStyle(

                      color: Colors.yellow,

                      fontSize: 48,

                      fontWeight: FontWeight.w700,

                      fontFamily: "SF UI Display",

                    ),

                    textAlign: TextAlign.start,

                  ),

                  IconButton(

                    icon: const Icon(Icons.update),

                    onPressed: () {

                      final ParseCloudFunction ticketSet =

                          ParseCloudFunction('linkTicketToUser');

                      ticketSet.execute();

                    },

                  ),

                ],

              ),

              const SizedBox(

                height: 10,

              ),

              Expanded(

                  child: ListView.builder(

                      itemCount: itemsData.length,

                      physics: BouncingScrollPhysics(),

                      itemBuilder: (context, index) {

                        double scale = 1.0;

                        return Opacity(

                          opacity: scale,

                          child: Align(

                              heightFactor: 0.7,

                              alignment: Alignment.topCenter,

                              child: itemsData[index]),

                        );

                      })),

            ],

          ),

        ),

      ),

    );

  }

}

ticket.dart


import 'dart:convert';

Ticket ticketFromJson(String str) => Ticket.fromJson(json.decode(str));

String ticketToJson(Ticket data) => json.encode(data.toJson());

class Ticket {
  Ticket({
    this.ticketHash,
    this.seat,
    this.row,
    this.section,
    this.event,
    this.auctionStatus,
    this.user,
    this.userObjectId,
  });

  int ticketHash;
  String seat;
  int row;
  int section;
  String event;
  bool auctionStatus;
  User user;
  String userObjectId;

  factory Ticket.fromJson(Map<String, dynamic> json) => Ticket(
        ticketHash: json["ticket_hash"],
        seat: json["seat"],
        row: json["row"],
        section: json["section"],
        event: json["event"],
        auctionStatus: json["auction_status"],
        user: User.fromJson(json["user"]),
        userObjectId: json["userObjectId"],
      );

  Map<String, dynamic> toJson() => {
        "ticket_hash": ticketHash,
        "seat": seat,
        "row": row,
        "section": section,
        "event": event,
        "auction_status": auctionStatus,
        "user": user.toJson(),
        "userObjectId": userObjectId,
      };
}

class User {
  User({
    this.type,
    this.className,
    this.objectId,
  });

  String type;
  String className;
  String objectId;

  factory User.fromJson(Map<String, dynamic> json) => User(
        type: json["__type"],
        className: json["className"],
        objectId: json["objectId"],
      );

  Map<String, dynamic> toJson() => {
        "__type": type,
        "className": className,
        "objectId": objectId,
      };
}

And what about the code that you wrote in order to transfer the object access?

I haven’t been able to figure out how to do the transfer for object access so that is why their is no code for it.

Is their a way where I can take the Ticket objectId and add it into the auction class and then the winning user at the end of the auction has their userId added to that ticket.

I don’t see why it couldn’t be done. I’d try to do that in cloud code. Maybe you should try to scratch something and share your progress so it would be easier for someone to help.