def list_ticket(request, event_id, ticket_num):
    """
    Tell the blockchain server that a venue wants to list a
    particular ticket with a given number of an event with
    the given id.
    """
    # get venue
    venue = get_object_or_404(Venue, user=request.user)

    # build data
    data = {
        "venue": {
            "venue_location": venue.location,
            "venue_name": venue.name
        },
        "event_id": event_id,
        "ticket_num": ticket_num
    }

    # send POST request to blockchain server with data
    response = bcAPI.post("venue/event/tickets/list", data=data)

    # expect 201 response if successful.
    if response[1] != 200:
        messages.error(request, "Couldn't list ticket.")
    else:
        messages.success(request, "Ticket successfully listed.")

    return redirect("home")
def buy_ticket(request, event_id, ticket_num):
    """
    Tell the blockchain server that the logged in customer intends 
    to purchase the ticket with the given ticket_num.
    """
    # get customer
    customer = get_object_or_404(Customer, user=request.user)
    event = get_object_or_404(Event, pk=event_id)
    venue = event.venue

    # build data
    data = {
        "user_email": customer.user.email,
        "event_id": event_id,
        "ticket_num": ticket_num,
        "venue": {
            "venue_location": venue.location,
            "venue_name": venue.name
        }
    }

    # send POST request to blockchain server with data.
    response = bcAPI.post("user/buy_ticket", data=data)

    # expect 200 response if successful.
    if response[1] != 200:
        messages.error(request, "Not enough funds to buy this ticket.")
    else:
        messages.success(request, "Ticket successfully purchased.")

    return redirect("home")
def list_customer_ticket(request, event_id, ticket_num):
    """
    List a ticket that a customer owns.
    """
    # get venue
    event = get_object_or_404(Event, pk=event_id)

    # build data
    data = {
        "venue": {
            "venue_location": event.venue.location,
            "venue_name": event.venue.name
        },
        "event_id": event_id,
        "ticket_num": ticket_num,
        "user_email": request.user.email
    }

    # send POST request to blockchain server with data
    response = bcAPI.post("user/list_ticket", data=data)

    # expect 201 response if successful.
    if response[1] != 200:
        messages.error(request, "Couldn't contact blockchain server.")
    else:
        messages.success(request, "Ticket successfully listed.")

    return redirect("list-customer-tickets")
def upgrade_ticket(request, event_id, ticket_num):
    customer = get_object_or_404(Customer, user=request.user)
    event = get_object_or_404(Event, pk=event_id)
    venue = event.venue

    if request.method == "POST":

        user_email = customer.user.email
        old_ticket_num = int(request.POST.get("current-ticket"))
        if old_ticket_num is None:
            # print('none')
            return redirect('upgrade-ticket')
        # TODO: send request to blockchain server to Upgrade ticket
        data = {
            "event_id": event_id,
            "ticket_num": old_ticket_num,
            "user_email": user_email,
            "new_ticket_num": ticket_num,
            "venue": {
                "venue_location": venue.location,
                "venue_name": venue.name
            }
        }
        # print(data)
        response = bcAPI.post("user/upgrade_ticket", data=data)
        if response[1] == 200:
            result = True
        else:
            result = False

        if result:
            messages.success(request, "Ticket upgraded.")
        else:
            messages.error(request, "Ticket not valid.")

        return redirect("list-customer-tickets")
    else:
        response = bcAPI.post("user/view_tickets",
                              data={"user_email": customer.user.email})
        if response[1] == 200:
            context = {"tickets": response[0], "event_id": int(event_id)}
        else:
            return redirect('home')
        return render(request, "customer_upgrade_ticket.html", context)
def search(request):
    query = request.GET.get("q")
    # print('query',query)
    date = request.GET.get("date")

    if date is None or date == "":
        date = None

    # print('date',date)
    date_range = request.GET.get("date-range")
    # print('date range',date_range)
    if date_range is None or date_range == "":
        date_range = None
    # print('date range',date_range)
    results = None

    if date or date_range or query:
        # empty query string is same as sending None
        if query == "":
            query = None

        if date:
            try:
                date = models.DateField().to_python(date)
            except:
                messages.error(request, "Invalid date format.")
                return redirect("search")

        data = {
            "user_email": request.user.email,
            "search_info": {
                "search_text": query,
                "date_range": int(date_range) if date_range else None,
                "date": {
                    "year": date.year,
                    "month": date.month,
                    "day": date.day
                } if date else None
            }
        }

        # print(data)

        response = bcAPI.post('user/search', data=data)

        if response[1] == 200:
            results = response[0]
        else:
            messages.error(request, "Something went wrong while searching. Please try again.")

    context = {
        "results": results,
        "query": query
    }

    return render(request, "search.html", context)
def event(request, event_id):
    """
    View for an event. A venue with the appropriate permissions can use
    this view to view tickets for an event.
    """
    try:
        event = Event.objects.get(pk=event_id)
    except Event.DoesNotExist:
        raise Http404("Event does not exist.")
    data =  {
                "venue": {
                    "venue_location": event.venue.location,
                    "venue_name": event.venue.name
                },
                "event_id": event_id
            }
    response = bcAPI.post('venue/view_event', data=data)
    e = response[0]
    tickets = []
    # TODO: get tickets by making API call to blockchain server
    # tickets = []
    try:
        user_venue = Venue.objects.get(user=request.user)
    except Venue.DoesNotExist as ex:
        user_venue = None

    # check if venue has the permissions to create tickets for
    # an event.
    # print("user venue: "+ str(user_venue))
    # print("event venue" + str(event.venue))
    # print(event.venue == user_venue)
    response = bcAPI.post('venue/event/view_tickets', data=data)
    tickets = response[0]


    # print(response)
    context = {
        "event": event,
        "tickets": tickets
    }

    return render(request, "event.html", context)
def wallet(request):
    context = {"balance": None}

    if not request.user.is_authenticated:
        return context

    try:
        venue = Venue.objects.get(user=request.user)

        data = {
            "venue": {
                "venue_location": venue.location,
                "venue_name": venue.name,
            }
        }

        response = bcAPI.post('venue/view_wallet', data=data)

        if response[1] == 200:
            context["balance"] = response[0]["wallet"]
        else:
            return context

    except Venue.DoesNotExist:
        try:
            customer = Customer.objects.get(user=request.user)

            data = {"user_email": customer.user.email}

            response = bcAPI.post('user/view_wallet', data=data)

            if response[1] == 200:
                context["balance"] = response[0]["wallet"]
            else:
                return context

        except Customer.DoesNotExist:
            pass

    return context
def edit_tickets(request, event_id):
    """
    Edit the price of a ticket given ticket number, section, and seat.
    """
    event = get_object_or_404(Event, pk=event_id)
    venue = get_object_or_404(Venue, user=request.user)

    if request.method == "POST":
        form = EditTicketsForm(request.POST)

        if form.is_valid():
            new_price = form.cleaned_data.get("face_value")
            section = form.cleaned_data.get("section")
            row = form.cleaned_data.get("row")
            seat_num = form.cleaned_data.get("seat")

            data = {
                "venue": {
                    "venue_location": venue.location,
                    "venue_name": venue.name
                },
                "event_id": event_id,
                "update_info": {
                    "new_price": new_price,
                    "which_seats": {
                        "section": section,
                        "row": str(row),
                        "seat_num": seat_num
                    }
                }
            }

            response = bcAPI.post('venue/event/tickets/edit', data=data)
            # print(response)
            if response[1] == 200:
                messages.success(request, "Tickets edited.")
            else:
                messages.error(request, "Failed to edit tickets.")

        else:
            messages.error(request, "Something went wrong.")
    else:
        form = EditTicketsForm()
    
    context = {
        "form": form,
        "event": event,
        "venue": venue
    }

    return render(request, "edit_tickets.html", context)
def edit_event(request, event_id):
    """
    Allows a venue to edit an event's date, time, and description.
    """
    event = get_object_or_404(Event, pk=event_id)

    if request.method == "POST":
        form = EditEventForm(request.POST, instance=event)

        if form.is_valid():
            venue = Venue.objects.get(user=request.user)
            event = form.save(commit=False)

            data = {
                "venue": {
                    "venue_location": venue.location,
                    "venue_name": venue.name
                },
                "event_id": event.id,
                "update_info": {
                    "name": event.name,
                    "desc": event.description,
                    "time": {
                        "minute": event.when.minute,
                        "hour": event.when.hour,
                        "day": event.when.day,
                        "month": event.when.month,
                        "year": event.when.year
                    }
                }
            }
            # print(data)

            response = bcAPI.post('venue/event/edit', data=data)
            # print(response)
            if response[0].get('event_id') == event.id:
                messages.success(request, "Event successfully edited.")
                event.save()
            else:
                messages.error(request, "Failed to edit event.")

            return redirect("venue", venue.id)
    else:
        form = EditEventForm(instance=event)

    context = {
        "form": form,
        "event": event
    }

    return render(request, "edit_event.html", context)
def schedule_release(request, event_id):
    """
    Schedule the release of the tickets for an event.
    """

    venue = get_object_or_404(Venue, user=request.user)
    event = get_object_or_404(Event, pk=event_id, venue=venue)

    if request.method == "POST":
        form = ScheduleReleaseForm(request.POST)

        if form.is_valid():
            date = form.cleaned_data.get("scheduled_for")
            section = form.cleaned_data.get('section')

        # TODO: send request to blockchain server indicating that
        # venue wants to schedule all the tickets.

        data = {
            "venue": {
                "venue_location": venue.location,
                "venue_name": venue.name
            },
            "event_id": event_id,
            "release_info": {
                "section": section,
                "release_date": {
                    "month": date.month,
                    "day": date.day,
                    "year": date.year
                }
            }
        }
        response = bcAPI.post("venue/schedule_release", data=data)

        if response[1] == "200":
            messages.success(request,
                             "The tickets have been successfully scheduled.")
        else:
            messages.error(request, "Ticket scheduling failed.")
    else:
        form = ScheduleReleaseForm()

    context = {"form": form, "event": event}

    return render(request,
                  template_name="schedule_release.html",
                  context=context)
def create_event(request):
    if request.method == "POST":
        form = CreateEventForm(request.POST)
        if form.is_valid():
            user = request.user
            venue = Venue.objects.get(user=user)
            name = form.cleaned_data.get("name")
            description = form.cleaned_data.get("description")
            when = form.cleaned_data.get("when")

            event = Event.objects.create(venue=venue, name=name, description=description)
            # print("event id: ", event.id)

            # TODO: API call to blockchain server to create event
            data = {
                "venue": {
                    "venue_location": venue.location,
                    "venue_name": venue.name
                },
                "name": name,
                "description": description,
                "event_id": event.id,
                "time": {
                    "minute": when.minute,
                    "hour": when.hour,
                    "day": when.day,
                    "month": when.month,
                    "year": when.year
                }
            }

            response = bcAPI.post('venue/event/create', data=data)
            if response[0].get('event_id') == event.id:
                messages.success(request, "Event successfully created.")
            else:
                # messages.failure(request, "Event non ")
                messages.error(request, "Failed to create event.")
                event.delete()

            return redirect("home")
    else:
        form = CreateEventForm()

    return render(request, "create_event.html", {"form": form})
def explore(request):
    user = request.user

    # TODO: submit request to blockchain server to get events for explore
    data = {
        "user_email": user.email
    }
    response = bcAPI.post('user/explore', data=data)

    if response[1] == 200:
        events = response[0]

        context = {
            "events": events
        }

        return render(request, "explore.html", context)
    else:
        messages.error(request, "Can't contact blockchain server.")
        return redirect("/")
def validate_ticket(request, event_id):
    venue = get_object_or_404(Venue, user=request.user)
    event = get_object_or_404(Event, pk=event_id, venue=venue)

    if request.method == "POST":
        form = ValidateTicketForm(request.POST)
        if form.is_valid():
            ticket_num = form.cleaned_data.get("ticket_num")
            h = form.cleaned_data.get("hsh")
            user_email = form.cleaned_data.get("user_email")

            # TODO: send request to blockchain server to validate ticket
            data = {
                "event_id": event_id,
                "ticket_num": ticket_num,
                "user_email": user_email,
                "hash": h,
                "venue": {
                    "venue_location": venue.location,
                    "venue_name": venue.name
                }
            }
            response = bcAPI.post("venue/event/tickets/validate", data=data)
            if response[1] == 200:
                result = True
            else:
                result = False

            if result:
                messages.success(request, "Ticket validated.")
            else:
                messages.error(request, "Ticket not valid.")

            return redirect("validate-ticket", event_id)
    else:
        form = ValidateTicketForm()

    context = {"venue": venue, "event": event, "form": form}

    return render(request, "validate_ticket.html", context)
def venue(request, venue_id):
    """
    View the events of a venue.
    """
    try:
        venue = Venue.objects.get(pk=venue_id)
    except Venue.DoesNotExist:
        raise Http404("Venue does not exist.")

    # TODO: get events from API call to blockchain server
    data = {
        "venue": {
            "venue_location": venue.location,
            "venue_name": venue.name
        }
    }
    response = bcAPI.post("venue/view_events", data=data)
    events = response[0]

    context = {"events": events, "venue": venue}

    return render(request, "venue.html", context)
def list_customer_tickets(request):
    """
    Return the list of tickets purchased by the currently logged
    in user.
    """

    # get customer
    customer = get_object_or_404(Customer, user=request.user)

    # use customer id to query blockchain server to
    # get the list of the customer's tickets.
    # Expect JSON response with list of tickets, each with the name
    # of the event, details of the seat, the ticket id (num), and the venue.
    # TODO
    response = bcAPI.post("user/view_tickets",
                          data={"user_email": customer.user.email})

    if response[1] != 200:  # request to blockchain server failed
        messages.error(request, "Couldn't contact blockchain server.")
        return redirect("home")

    context = {"tickets": response[0]}

    return render(request, "customer_ticket_list.html", context)
def register(request):
    # if user is already logged in, redirect to home page
    if request.user.is_authenticated:
        return redirect("home")

    if request.method == "POST":
        form = RegisterForm(request.POST)
        csrf_token = get_token(request)


        if form.is_valid():
            email = form.cleaned_data.get("email")
            password1 = form.cleaned_data.get("password1")
            password2 = form.cleaned_data.get("password2")
            user_type = form.cleaned_data.get("user_type")
            name = form.cleaned_data.get("name")
            bc_created = False
            if password1 == password2:

                if user_type == "venue":
                    data = {
                        "venue_location": "Chicago, IL",
                        "venue_name": name
                    }
                    response = bcAPI.post('venue/create', data=data)
                    if response[1] == 200:
                        user = User.objects.create_user(email=email, password=password1)
                        Venue.objects.create(user=user, name=name, location="Chicago, IL")
                        bc_created = True
                    else:
                        messages.error(request, "Request to blockchain API failed.")
                        # print(response[1])
                        return redirect("register")

                else:
                    data = {
                        "fname": name,
                        "lname": "smith",
                        "email_address": email
                    }
                    response = bcAPI.post('user/create', data=data)
                    if response[1] == 200:
                        bc_created = True
                        user = User.objects.create_user(email=email, password=password1)
                        Customer.objects.create(user=user, name=name)
                    else:
                        messages.error(request, "Request to blockchain API failed.")
                        return redirect("register")
            else:
                messages.error(request, "Passwords do not match.")
                return redirect("register")

            if bc_created:
                user = authenticate(email=email, password=password1)
                auth_login(request, user)

            return redirect("home")
    else:
        form = RegisterForm()

    return render(request, "register.html", {"form": form})
def create_tickets(request, event_id):
    try:
        event = Event.objects.get(pk=event_id)
    except Event.DoesNotExist:
        raise Http404("Event does not exist.")

    if request.method == "POST":
        form = CreateTicketsForm(request.POST)
        if form.is_valid():
            # getting data from form
            section = form.cleaned_data.get("section")
            min_row = form.cleaned_data.get("min_row")
            max_row = form.cleaned_data.get("max_row")
            min_seat = form.cleaned_data.get('min_seat')
            max_seat = form.cleaned_data.get('max_seat')
            face_value = form.cleaned_data.get('face_value')


            venue = Venue.objects.get(user=request.user)

            # check if venue has the permissions to create tickets for
            # an event.
            if event.venue == venue:
                # TODO: API call to blockchain server to create tickets
                data = {
                    "venue": {
                            "venue_location": venue.location,
                            "venue_name": venue.name
                    },
                    "event_id": event.id,
                    "tickets_info": {
                        "face_value": face_value,
                        "section": section,
                        "row_range": {
                            "begin": min_row,
                            "end": max_row
                        },
                        "seat_range": {
                            "begin": min_seat,
                            "end": max_seat
                        }
                    }
                }
                response = bcAPI.post('venue/event/tickets/create',data=data)
                messages.success(
                    request, "Tickets successfully created."
                )
                # print(response[0])

                return redirect("create-tickets", event.pk)
            else:
                messages.error(
                    request,
                    "You are not authorized to create tickets for this event."
                )

                return redirect("home")
    else:
        form = CreateTicketsForm()

    context = {
        "form": form,
        "event": event
    }

    return render(request, "create_tickets.html", context)