• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gcivil-nyu-org / wed-fall24-team5 / 628699075

04 Dec 2024 02:58AM UTC coverage: 90.579% (-0.4%) from 90.962%
628699075

push

github

web-flow
refactor image sizes and drive dashboard ui (#381)

* refactor image sizes and drive dashboard ui

* fix js data reload on modify and delete contribution

1 of 11 new or added lines in 1 file covered. (9.09%)

6 existing lines in 2 files now uncovered.

2798 of 3089 relevant lines covered (90.58%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.82
/src/donor_dashboard/views.py
1
from django.shortcuts import render, redirect, get_object_or_404  # noqa
1✔
2
from django.db.models import Prefetch
1✔
3
from database.models import (
1✔
4
    DietaryRestriction,
5
    Organization,
6
    OrganizationAdmin,
7
    User,
8
    Donation,
9
    Order,
10
    UserReview,
11
)
12
from django.contrib import messages
1✔
13
from donor_dashboard.forms import AddOrganizationForm, AddDonationForm
1✔
14
from django.contrib.auth.decorators import login_required
1✔
15
from django.contrib.auth.hashers import make_password
1✔
16
from django.utils import timezone
1✔
17
from django.utils.crypto import get_random_string
1✔
18
from django.http import HttpResponse, JsonResponse
1✔
19
from django.db.models import Avg, Count, F, Value
1✔
20
from django.db.models.functions import ExtractMonth, TruncDate, Coalesce
1✔
21
from .helpers import validate_donation
1✔
22
import csv
1✔
23
from itertools import chain
1✔
24
from operator import attrgetter
1✔
25
import json
1✔
26
import base64
1✔
27
from django.utils.timezone import now
1✔
28

29

30
@login_required
1✔
31
def get_org_info(request, organization_id):
1✔
32
    organization = Organization.objects.get(organization_id=organization_id)
1✔
33
    donations = Donation.objects.filter(
1✔
34
        organization_id=organization.organization_id, active=True
35
    )
36
    orders = Order.objects.filter(donation__organization=organization).prefetch_related(
1✔
37
        "donation"
38
    )
39
    reviews = (
1✔
40
        UserReview.objects.filter(donation__organization=organization)
41
        .order_by("modified_at")
42
        .values("rating", "comment")
43
    )
44
    rating = reviews.aggregate(avg=Avg("rating"))["avg"]
1✔
45
    num_users = orders.values("user").distinct().count()
1✔
46

47
    return donations, orders, reviews, rating, num_users
1✔
48

49

50
@login_required
1✔
51
def get_org_list(request):
1✔
52
    if request.method == "POST":
1✔
53
        form = AddOrganizationForm(request.POST)
1✔
54
        if form.is_valid():
1✔
55
            organization = form.save()
1✔
56
            org_user = User.objects.get(email=request.user.email)
1✔
57
            OrganizationAdmin.objects.create(
1✔
58
                user=org_user, organization=organization, access_level="owner"
59
            )
60
            messages.success(request, "Organization successfully added.")
1✔
61
            return redirect("/donor_dashboard")
1✔
62
        else:
63
            # Handle errors using Django messages
64
            if form.errors.get("organization_name"):
1✔
65
                messages.warning(
1✔
66
                    request, "Organization Name is invalid. Please try again."
67
                )
68
            if form.errors.get("address"):
1✔
69
                messages.warning(request, "Address is not valid. Please try again.")
×
70
            if form.errors.get("zipcode"):
1✔
71
                messages.warning(request, "Zipcode is not valid. Please try again.")
1✔
72
            if form.errors.get("contact_number"):
1✔
73
                messages.warning(
×
74
                    request, "Contact Number is not valid. Please try again."
75
                )
76
            if form.errors.get("email"):
1✔
77
                messages.warning(request, "Email is not valid. Please try again.")
×
78
            if form.errors.get("website"):
1✔
79
                messages.warning(request, "Website is not valid. Please try again.")
×
80
            if form.errors.get("__all__"):
1✔
81
                messages.warning(
1✔
82
                    request,
83
                    "An organization with the same details already exists. Please modify at least one field and try again.",
84
                )
85

86
            # Fallback error message
87
            if not any(form.errors):
1✔
88
                messages.warning(
×
89
                    request, "Registration failed. Please check the form for errors."
90
                )
91

92
            # Pass the form with errors back to the template
93
            return redirect("/donor_dashboard")
1✔
94
    else:
95
        form = AddOrganizationForm()
1✔
96

97
    org_user = User.objects.get(email=request.user.email)
1✔
98
    organization_admin_list = OrganizationAdmin.objects.filter(user=org_user)
1✔
99
    active_org_list = []
1✔
100
    inactive_org_list = []
1✔
101

102
    for organization_admin in organization_admin_list:
1✔
103
        organization = organization_admin.organization
1✔
104
        obj = {
1✔
105
            "org_id": organization.organization_id,
106
            "org_name": organization.organization_name,
107
            "org_type": organization.type,
108
            "org_address": organization.address,
109
            "org_zipcode": organization.zipcode,
110
            "org_email": organization.email,
111
            "org_website": organization.website,
112
            "org_contact_number": organization.contact_number,
113
            "access_level": organization_admin.access_level,
114
        }
115
        if organization.active:
1✔
116
            active_org_list.append(obj)
1✔
117
        else:
118
            inactive_org_list.append(obj)
×
119

120
    return render(
1✔
121
        request,
122
        "donor_dashboard/list.html",
123
        {
124
            "active_org_list": active_org_list,
125
            "inactive_org_list": inactive_org_list,
126
            "form": form,
127
        },
128
    )
129

130

131
@login_required
1✔
132
def manage_organization(request, organization_id):
1✔
133
    # Fetch the organization using the organization_id
134
    try:
1✔
135
        organization = Organization.objects.get(organization_id=organization_id)
1✔
136
        org_user = User.objects.get(email=request.user.email)
1✔
137
        organization_admin = OrganizationAdmin.objects.get(
1✔
138
            user=org_user, organization=organization
139
        )
140
        access_level = organization_admin.access_level
1✔
141
        if access_level == "owner":
1✔
142
            owner_access = True
1✔
143
        else:
144
            owner_access = False
1✔
145

146
        update_donations()
1✔
147
        cancel_expired_orders()
1✔
148

149
        # Fetch donations with related reviews
150
        donations = Donation.objects.filter(
1✔
151
            organization_id=organization.organization_id,
152
            active=True,
153
        )
154

155
        reviewed_donations = get_donations_with_reviews(organization.organization_id)
1✔
156

157
        # Prefetch orders and dietary restrictions for each user
158
        orders = (
1✔
159
            Order.objects.filter(
160
                donation__organization=organization, order_status="pending"
161
            )
162
            .prefetch_related(
163
                "donation",
164
                "user",
165
                Prefetch(
166
                    "user__dietaryrestriction_set",
167
                    queryset=DietaryRestriction.objects.all(),
168
                    to_attr="dietary_restrictions",
169
                ),
170
            )
171
            .order_by("-donation__pickup_by", "donation__donation_id")
172
        )
173

174
        # Process dietary restrictions to replace underscores and apply title case
175
        for order in orders:
1✔
176
            if hasattr(order.user, "dietary_restrictions"):
1✔
177
                for restriction in order.user.dietary_restrictions:
1✔
178
                    restriction.restriction = restriction.restriction.replace(
1✔
179
                        "_", " "
180
                    ).title()
181

182
        status = organization.active
1✔
183
        reviews = (
1✔
184
            UserReview.objects.filter(donation__organization=organization)
185
            .order_by("modified_at")
186
            .values("rating", "comment")
187
        )
188

189
        rating = reviews.aggregate(avg=Avg("rating"))["avg"]
1✔
190
        num_users = orders.values("user").distinct().count()
1✔
191
        form = AddDonationForm()
1✔
192
        return render(
1✔
193
            request,
194
            "donor_dashboard/manage_organization.html",
195
            {
196
                "organization": organization,
197
                "donations": donations,
198
                "status": status,
199
                "orders": orders,
200
                "owner_access": owner_access,
201
                "reviews": reviews,
202
                "rating": rating,
203
                "reviewed_donations": reviewed_donations,
204
                "num_users": num_users,
205
                "form": form,
206
            },
207
        )
208
    except Exception:
×
209
        messages.warning(request, "You Don't have permission to do this action")
×
210
        return redirect(
×
211
            "donor_dashboard:org_list",
212
        )
213

214

215
@login_required
1✔
216
def organization_details(request, organization_id):
1✔
217
    try:
1✔
218
        organization = Organization.objects.get(organization_id=organization_id)
1✔
219
        current_user = User.objects.get(email=request.user.email)
1✔
220
        current_org_admin = OrganizationAdmin.objects.get(
1✔
221
            user=current_user, organization=organization
222
        )
223

224
        if current_org_admin.access_level == "owner":
1✔
225
            organization_admins = OrganizationAdmin.objects.filter(
1✔
226
                organization_id=organization_id
227
            ).order_by("-access_level")
228

229
            if request.method == "POST":
1✔
230
                form = AddOrganizationForm(request.POST, instance=organization)
1✔
231
                if form.is_valid():
1✔
232
                    organization = form.save()
1✔
233
                    messages.success(
1✔
234
                        request, "Organization Details Updated Succesfully."
235
                    )
236
                    return redirect(
1✔
237
                        "donor_dashboard:manage_organization",
238
                        organization_id=organization_id,
239
                    )
240
                else:
UNCOV
241
                    messages.warning(
×
242
                        request, "Something went wrong, please enter valid inputs"
243
                    )
UNCOV
244
                    organization = Organization.objects.get(
×
245
                        organization_id=organization_id
246
                    )
UNCOV
247
                    form = AddOrganizationForm(instance=organization)
×
248
            else:
249
                form = AddOrganizationForm(instance=organization)
1✔
250

251
            organization_admins = OrganizationAdmin.objects.filter(
1✔
252
                organization_id=organization_id
253
            )
254
            admins = []
1✔
255
            for organization_admin in organization_admins:
1✔
256
                org_user = organization_admin.user
1✔
257
                if org_user != current_user:
1✔
258
                    if org_user.first_name and org_user.last_name:
1✔
259
                        name = org_user.first_name + " " + org_user.last_name
×
260
                    else:
261
                        name = org_user.email.split("@")[0]
1✔
262
                    admins.append(
1✔
263
                        {
264
                            "name": name,
265
                            "email": organization_admin.user.email,
266
                            "access_level": organization_admin.access_level,
267
                            "created_at": organization_admin.created_at,
268
                        }
269
                    )
270

271
            owner_count = organization_admins.filter(access_level="owner").count()
1✔
272
            multiple_owners = owner_count > 1
1✔
273

274
            return render(
1✔
275
                request,
276
                "donor_dashboard/organization_details.html",
277
                {
278
                    "organization": organization,
279
                    "form": form,
280
                    "current_org_admin": current_org_admin,
281
                    "admins": admins,
282
                    "multiple_owners": multiple_owners,
283
                },
284
            )
285
        else:
286
            messages.warning(request, "You don't have permission to do this action")
×
287
            return redirect(
×
288
                "donor_dashboard:manage_organization", organization_id=organization_id
289
            )
290
    except Exception:
×
291
        messages.warning(request, "You don't have permission to do this action")
×
292
        return redirect(
×
293
            "donor_dashboard:manage_organization", organization_id=organization_id
294
        )
295

296

297
@login_required
1✔
298
def delete_organization(request, organization_id):
1✔
299
    if request.method == "POST":
1✔
300
        organization = Organization.objects.get(organization_id=organization_id)
1✔
301

302
        # Set the active field in Donations to False for soft delete
303
        donations = Donation.objects.filter(organization=organization)
1✔
304
        for donation in donations:
1✔
305

306
            # Set the active field in Orders to False for soft delete
307
            orders = Order.objects.filter(donation=donation)
1✔
308
            for order in orders:
1✔
309
                order.active = False
1✔
310
                order.save()
1✔
311

312
            donation.active = False
1✔
313
            donation.save()
1✔
314

315
        # Set the active field in Organization to False for soft delete
316
        organization.active = False
1✔
317
        organization.save()
1✔
318

319
        organization_name = organization.organization_name
1✔
320

321
        messages.success(
1✔
322
            request, f'Organization "{organization_name}" made inactive successfully.'
323
        )
324
        return redirect("donor_dashboard:org_list")
1✔
325
    return redirect("donor_dashboard:org_list")
×
326

327

328
@login_required
1✔
329
def filter_statistics(request, organization_id):
1✔
330
    organization = Organization.objects.get(organization_id=organization_id)
×
331
    donations = Donation.objects.filter(
×
332
        organization_id=organization.organization_id, active=True
333
    )
334
    grouped_donations = (
×
335
        donations.annotate(month=ExtractMonth("created_at"))
336
        .values("month")
337
        .order_by("-month")
338
        .distinct()
339
    )
340
    options = [donation["month"] for donation in grouped_donations]
×
341
    return JsonResponse(
×
342
        {
343
            "options": options,
344
        }
345
    )
346

347

348
@login_required
1✔
349
def statistics_orders(request, organization_id):
1✔
350
    organization = Organization.objects.get(organization_id=organization_id)
1✔
351
    orders = Order.objects.filter(donation__organization=organization).prefetch_related(
1✔
352
        "donation"
353
    )
354
    orders_data = (
1✔
355
        orders.annotate(date=TruncDate("order_created_at"))
356
        .values("date")
357
        .annotate(order_count=Count("order_id"))
358
        .order_by("date")
359
    )
360
    dates = [entry["date"].strftime("%b %d") for entry in orders_data]
1✔
361
    orders_counts = [entry["order_count"] for entry in orders_data]
1✔
362

363
    return JsonResponse(
1✔
364
        data={
365
            "labels": dates,
366
            "data": orders_counts,
367
        }
368
    )
369

370

371
@login_required
1✔
372
def statistics_orders_status(request, organization_id):
1✔
373
    organization = Organization.objects.get(organization_id=organization_id)
1✔
374
    orders = Order.objects.filter(donation__organization=organization).prefetch_related(
1✔
375
        "donation"
376
    )
377
    statuses = {
1✔
378
        "picked_up": "Picked Up",
379
        "pending": "Pending",
380
        "canceled": "Canceled",
381
    }
382
    orders_status_data = orders.values("order_status").annotate(
1✔
383
        order_count=Count("order_id")
384
    )
385

386
    status_counts_dict = {
1✔
387
        item["order_status"]: item["order_count"] for item in orders_status_data
388
    }
389
    order_statuses = [statuses[status] for status in statuses.keys()]
1✔
390
    data = [status_counts_dict.get(order_status, 0) for order_status in statuses.keys()]
1✔
391

392
    return JsonResponse(
1✔
393
        data={
394
            "labels": order_statuses,
395
            "data": data,
396
        }
397
    )
398

399

400
@login_required
1✔
401
def statistics_donations(request, organization_id):
1✔
402
    organization = Organization.objects.get(organization_id=organization_id)
1✔
403
    donations = Donation.objects.filter(
1✔
404
        organization_id=organization.organization_id, active=True
405
    )
406
    donations_data = (
1✔
407
        donations.annotate(date=TruncDate("created_at"))
408
        .values("date")
409
        .annotate(order_count=Count("donation_id"))
410
        .order_by("date")
411
    )
412
    dates = [entry["date"].strftime("%b %d") for entry in donations_data]
1✔
413
    donations_counts = [entry["order_count"] for entry in donations_data]
1✔
414

415
    return JsonResponse(
1✔
416
        data={
417
            "labels": dates,
418
            "data": donations_counts,
419
        }
420
    )
421

422

423
@login_required
1✔
424
def statistics_ratings(request, organization_id):
1✔
425
    organization = Organization.objects.get(organization_id=organization_id)
1✔
426
    reviews = (
1✔
427
        UserReview.objects.filter(donation__organization=organization)
428
        .order_by("modified_at")
429
        .values("rating", "comment")
430
    )
431
    ratings_data = (
1✔
432
        reviews.values("rating")
433
        .annotate(rating_count=Coalesce(Count("review_id"), Value(0)))
434
        .order_by("rating")
435
    )
436
    # ratings = [entry["rating"] for entry in ratings_data]
437
    # ratings_counts = [entry["rating_count"] for entry in ratings_data]
438
    all_ratings = {i: 0 for i in range(1, 6)}
1✔
439
    for entry in ratings_data:
1✔
440
        rating = entry["rating"]
1✔
441
        count = entry["rating_count"]
1✔
442
        all_ratings[rating] = count
1✔
443

444
    return JsonResponse(
1✔
445
        data={
446
            "labels": list(all_ratings.keys()),
447
            "data": list(all_ratings.values()),
448
        }
449
    )
450

451

452
@login_required
1✔
453
def organization_statistics(request, organization_id):
1✔
454
    organization = Organization.objects.get(organization_id=organization_id)
1✔
455
    donations, orders, reviews, rating, num_users = get_org_info(
1✔
456
        request, organization_id
457
    )
458
    orders = orders.annotate(created_date=F("order_created_at"), type=Value("Order"))
1✔
459
    review_data = UserReview.objects.filter(
1✔
460
        donation__organization=organization
461
    ).annotate(created_date=F("created_at"), type=Value("Review"))
462
    activity_feed = sorted(
1✔
463
        chain(orders, review_data), key=attrgetter("created_date"), reverse=True
464
    )
465
    return render(
1✔
466
        request,
467
        "donor_dashboard/statistics.html",
468
        {
469
            "organization": organization,
470
            "donations": donations,
471
            "orders": orders,
472
            "reviews": reviews,
473
            "rating": rating,
474
            "num_users": num_users,
475
            "activity_feed": activity_feed,
476
        },
477
    )
478

479

480
@login_required
1✔
481
def add_donation(request):
1✔
482
    if request.method == "POST":
1✔
483
        organization_id = request.POST.get("organization")
1✔
484
        organization_id = organization_id.strip()
1✔
485
        form = AddDonationForm(request.POST)
1✔
486

487
        if form.is_valid():
1✔
488
            donation = form.save(commit=False)
1✔
489
            food_item = form.cleaned_data["food_item"]
1✔
490
            organization = Organization.objects.get(organization_id=organization_id)
1✔
491
            donation.organization = organization
1✔
492
            donation.save()
1✔
493
            messages.success(request, f"Donation: {food_item} added successfully!")
1✔
494

495
        else:
496
            messages.error(request, "Unable to add donation.")
1✔
497

498
        return redirect(
1✔
499
            "donor_dashboard:manage_organization", organization_id=organization_id
500
        )
501

502
    messages.warning(request, "Invalid Add Donation Request!")
1✔
503
    return redirect("/")
1✔
504

505

506
@login_required
1✔
507
def modify_donation(request, donation_id):
1✔
508
    donation = get_object_or_404(Donation, donation_id=donation_id)
1✔
509
    if request.method == "POST":
1✔
510
        food_item = request.POST["food_item"]
1✔
511
        quantity = request.POST.get("quantity")
1✔
512
        pickup_by = request.POST.get("pickup_by")
1✔
513
        organization_id = request.POST.get("organization")
1✔
514
        organization_id = organization_id.strip()
1✔
515

516
        # Use the validation function
517
        errors = validate_donation(food_item, quantity, pickup_by, organization_id)
1✔
518
        if errors:
1✔
519
            for error in errors:
1✔
520
                messages.warning(request, error)
1✔
521
            return redirect(
1✔
522
                "donor_dashboard:manage_organization", organization_id=organization_id
523
            )
524

525
        # Update donation if all validations pass
526
        donation.food_item = food_item
1✔
527
        donation.quantity = int(quantity)  # Convert to integer before saving
1✔
528
        donation.pickup_by = timezone.datetime.strptime(pickup_by, "%Y-%m-%d").date()
1✔
529
        donation.organization_id = organization_id
1✔
530
        donation.save()
1✔
531

532
        messages.success(request, f"Donation: {food_item} modified successfully!")
1✔
533
        return redirect(
1✔
534
            "donor_dashboard:manage_organization", organization_id=organization_id
535
        )
536

537
    messages.warning(request, "Invalid Modify Donation Request!")
×
538
    return redirect(
×
539
        "donor_dashboard:manage_organization", organization_id=donation.organization_id
540
    )
541

542

543
@login_required
1✔
544
def delete_donation(request, donation_id):
1✔
545
    donation = get_object_or_404(Donation, donation_id=donation_id)
1✔
546
    if request.method == "POST":
1✔
547
        donation.active = False  # Set the active field to False for soft delete
1✔
548
        donation.quantity = 0
1✔
549
        donation.save()
1✔
550

551
        messages.success(
1✔
552
            request, f"Donation '{donation.food_item}' has been deleted successfully!"
553
        )
554
        return redirect(
1✔
555
            "donor_dashboard:manage_organization",
556
            organization_id=donation.organization_id,
557
        )
558

559
    messages.error(request, "Invalid Delete Donation Request!")
1✔
560
    return redirect(
1✔
561
        "donor_dashboard:manage_organization", organization_id=donation.organization_id
562
    )
563

564

565
@login_required
1✔
566
def manage_order(request, order_id):
1✔
567
    order = get_object_or_404(Order, order_id=order_id)
×
568
    donation = Donation.objects.get(donation_id=order.donation_id)
×
569

570
    order.order_status = "picked_up" if order.order_status == "pending" else "pending"
×
571
    order.save()
×
572

573
    return redirect(
×
574
        "donor_dashboard:manage_organization",
575
        organization_id=donation.organization_id,
576
    )
577

578

579
def sanitize_csv_field(value):
1✔
580
    """
581
    Escape potential CSV injection by adding a single quote
582
    to values starting with special characters. Convert non-string values to strings.
583
    """
584
    if not isinstance(value, str):
1✔
585
        value = str(value)
1✔
586

587
    # List of potentially dangerous prefixes
588
    dangerous_prefixes = ("=", "+", "-", "@", "\t", "\n")
1✔
589

590
    # If value starts with any dangerous prefix, prepend a single quote
591
    if value.startswith(dangerous_prefixes):
1✔
592
        return f"'{value}"
×
593
    return value
1✔
594

595

596
def sanitize_order(order, organization):
1✔
597
    """
598
    Sanitizes all the fields of an order object and returns a list of sanitized fields.
599
    """
600
    return [
1✔
601
        sanitize_csv_field(order.donation.food_item if order.donation else ""),
602
        sanitize_csv_field(order.user.email if order.user else ""),
603
        sanitize_csv_field(
604
            f"{order.user.first_name} {order.user.last_name}" if order.user else ""
605
        ),
606
        sanitize_csv_field(order.order_quantity),
607
        sanitize_csv_field(
608
            order.donation.pickup_by.strftime("%Y-%m-%d")
609
            if order.donation and order.donation.pickup_by
610
            else ""
611
        ),
612
        sanitize_csv_field(organization.address),
613
        sanitize_csv_field(order.order_status),
614
        sanitize_csv_field(
615
            order.order_created_at.strftime("%Y-%m-%d %H:%M:%S")
616
            if order.order_created_at
617
            else ""
618
        ),
619
        sanitize_csv_field(
620
            order.order_modified_at.strftime("%Y-%m-%d %H:%M:%S")
621
            if order.order_modified_at
622
            else ""
623
        ),
624
    ]
625

626

627
@login_required
1✔
628
def download_orders(request, organization_id):
1✔
629
    organization = Organization.objects.get(organization_id=organization_id)
1✔
630
    # Order by creation date (most recent first)
631
    orders = (
1✔
632
        Order.objects.filter(donation__organization=organization)
633
        .prefetch_related("donation", "user")
634
        .order_by("-donation__pickup_by")
635
    )
636
    current_date = timezone.now().strftime("%Y%m%d")
1✔
637

638
    response = HttpResponse(content_type="text/csv")
1✔
639
    filename = f"{organization.organization_id}_orders_{current_date}.csv"
1✔
640
    response["Content-Disposition"] = f'attachment; filename="{filename}"'
1✔
641

642
    writer = csv.writer(response)
1✔
643
    writer.writerow(
1✔
644
        [
645
            "Item",
646
            "Reserved By (Email)",
647
            "Reserved By (Name)",
648
            "Quantity",
649
            "Pickup Date",
650
            "Address",
651
            "Order Status",
652
            "Order Created On",
653
            "Order Modified On",
654
        ]
655
    )
656

657
    for order in orders:
1✔
658
        sanitized_order = sanitize_order(order, organization)
1✔
659
        writer.writerow(sanitized_order)
1✔
660

661
    return response
1✔
662

663

664
@login_required
1✔
665
def add_org_admin(request):
1✔
666
    try:
1✔
667
        organization_id = request.POST["organization_id"]
1✔
668
        new_admin_email = request.POST.get("email")
1✔
669
        organization = Organization.objects.get(organization_id=organization_id)
1✔
670
        current_user = User.objects.get(email=request.user.email)
1✔
671
        current_org_admin = OrganizationAdmin.objects.get(
1✔
672
            user=current_user, organization=organization
673
        )
674
        if current_org_admin.access_level == "owner":
1✔
675
            if request.method == "POST":
1✔
676
                new_admin_user, created = User.objects.get_or_create(
1✔
677
                    email=new_admin_email
678
                )
679
                if created:
1✔
680
                    new_admin_user.username = new_admin_email  # Set username as email
×
681
                    default_password = get_random_string(8)
×
682
                    new_admin_user.password = make_password(default_password)
×
683
                    new_admin_user.save()  # Save the user object
×
684
                if (
1✔
685
                    len(
686
                        OrganizationAdmin.objects.filter(
687
                            user=new_admin_user, organization=organization
688
                        )
689
                    )
690
                    == 0
691
                    or created
692
                ):
693
                    OrganizationAdmin.objects.create(
1✔
694
                        user=new_admin_user,
695
                        organization=organization,
696
                        access_level="admin",
697
                    )
698
                    if created:
1✔
699
                        messages.add_message(
×
700
                            request,
701
                            messages.INFO,
702
                            f"Admin successfully created with default password: {default_password}",
703
                            extra_tags="temp_password",
704
                        )
705
                    else:
706
                        messages.success(request, "Admin successfully added.")
1✔
707
                else:
708
                    messages.success(request, "Admin already associated")
1✔
709
            return redirect(
1✔
710
                "donor_dashboard:organization_details", organization_id=organization_id
711
            )
712
        else:
713
            messages.warning(request, "You Don't have permission to do this action")
1✔
714
            return redirect(
1✔
715
                "donor_dashboard:manage_organization", organization_id=organization_id
716
            )
717
    except Exception:
×
718
        messages.warning(request, "You Don't have permission to do this action")
×
719
        return redirect(
×
720
            "donor_dashboard:manage_organization", organization_id=organization_id
721
        )
722

723

724
@login_required
1✔
725
def check_user(request):
1✔
726
    if request.method == "POST":
1✔
727
        data = json.loads(request.body)
1✔
728
        email = data.get("email")
1✔
729
        exists = User.objects.filter(email=email).exists()
1✔
730
        return JsonResponse({"exists": exists})
1✔
731

732

733
@login_required
1✔
734
def assign_organization_access_level(
1✔
735
    request, organization_id, admin_email, current_access_level
736
):
737
    try:
1✔
738
        organization = Organization.objects.get(organization_id=organization_id)
1✔
739
        current_user = User.objects.get(email=request.user.email)
1✔
740
        current_org_admin = OrganizationAdmin.objects.get(
1✔
741
            user=current_user, organization=organization
742
        )
743

744
        # Check if current user is the only owner
745
        owner_count = OrganizationAdmin.objects.filter(
1✔
746
            organization=organization, access_level="owner"
747
        ).count()
748

749
        if current_org_admin.access_level == "owner":
1✔
750
            if current_access_level == "owner" and owner_count == 1:
1✔
751
                # Prevent downgrading the only owner
752
                messages.warning(request, "You cannot remove the only owner.")
×
753
                return redirect(
×
754
                    "donor_dashboard:organization_details",
755
                    organization_id=organization_id,
756
                )
757

758
        if current_org_admin.access_level == "owner":
1✔
759
            if request.method == "POST":
1✔
760
                admin_user = User.objects.get(email=admin_email)
1✔
761
                organization_admin = OrganizationAdmin.objects.get(
1✔
762
                    user=admin_user, organization=organization
763
                )
764
                if current_access_level == "owner":
1✔
765
                    organization_admin.access_level = "admin"
×
766
                elif current_access_level == "admin":
1✔
767
                    organization_admin.access_level = "owner"
1✔
768

769
                organization_admin.save()
1✔
770

771
                messages.success(
1✔
772
                    request,
773
                    f"Succesfully made user with email: {admin_email} as {organization_admin.access_level}",
774
                )
775
            return redirect(
1✔
776
                "donor_dashboard:organization_details", organization_id=organization_id
777
            )
778
        else:
779
            messages.warning(request, "You Don't have permission to do this action")
×
780
            return redirect(
×
781
                "donor_dashboard:manage_organization", organization_id=organization_id
782
            )
783
    except Exception:
×
784
        messages.warning(request, "You Don't have permission to do this action")
×
785
        return redirect(
×
786
            "donor_dashboard:manage_organization", organization_id=organization_id
787
        )
788

789

790
@login_required
1✔
791
def remove_admin_owner(request, organization_id, admin_email):
1✔
792
    try:
1✔
793
        organization = Organization.objects.get(organization_id=organization_id)
1✔
794
        current_user = User.objects.get(email=request.user.email)
1✔
795
        current_org_admin = OrganizationAdmin.objects.get(
1✔
796
            user=current_user, organization=organization
797
        )
798
        if current_org_admin.access_level == "owner":
1✔
799
            if request.method == "POST":
1✔
800
                admin_user = User.objects.get(email=admin_email)
1✔
801
                organization_admin = OrganizationAdmin.objects.get(
1✔
802
                    user=admin_user, organization=organization
803
                )
804
                organization_admin.delete()
1✔
805

806
                messages.success(
1✔
807
                    request,
808
                    f"Succesfully remove this org access to email: {admin_email}",
809
                )
810
            return redirect(
1✔
811
                "donor_dashboard:organization_details", organization_id=organization_id
812
            )
813
        else:
814
            messages.warning(request, "You Don't have permission to do this action")
×
815
            return redirect(
×
816
                "donor_dashboard:manage_organization", organization_id=organization_id
817
            )
818
    except Exception:
×
819
        messages.warning(request, "You Don't have permission to do this action")
×
820
        return redirect(
×
821
            "donor_dashboard:manage_organization", organization_id=organization_id
822
        )
823

824

825
@login_required
1✔
826
def upload_donation_image(request):
1✔
827
    if request.method == "POST":
1✔
828
        donation_id = request.POST.get("donation_id")
1✔
829
        image = request.FILES.get("image")
1✔
830

831
        if not donation_id or not image:
1✔
832
            return JsonResponse({"success": False, "error": "Invalid data."})
1✔
833

834
        try:
1✔
835
            # Convert image to base64 string
836
            image_data = base64.b64encode(image.read()).decode("utf-8")
1✔
837

838
            # Update the donation object with the image string
839
            donation = Donation.objects.get(donation_id=donation_id)
1✔
840
            donation.image_data = (
1✔
841
                image_data  # Assuming `image_data` is a TextField in the model
842
            )
843
            donation.save()
1✔
844

845
            return JsonResponse({"success": True, "image_data": image_data})
1✔
846
        except Donation.DoesNotExist:
1✔
847
            return JsonResponse({"success": False, "error": "Donation not found."})
1✔
848
    return JsonResponse({"success": False, "error": "Invalid request method."})
1✔
849

850

851
def update_donations():
1✔
852
    """
853
    Updates the donations to keep only those with pickup dates today or later as active.
854
    All other donations will be marked as inactive.
855
    """
856
    today = now().date()  # Get the current date
1✔
857

858
    # Filter donations with pickup dates today or later and ensure they are active
859
    Donation.objects.filter(pickup_by__gte=today).update(active=True)
1✔
860

861
    # Mark donations with pickup dates before today as inactive
862
    Donation.objects.filter(pickup_by__lt=today).update(active=False)
1✔
863

864

865
def cancel_expired_orders():
1✔
866
    """
867
    Updates the status of all pending orders to 'canceled' if the pickup date has expired.
868
    """
869
    today = now().date()  # Get the current date
1✔
870

871
    # Identify orders with expired pickup dates and 'pending' status
872
    expired_orders = Order.objects.filter(
1✔
873
        donation__pickup_by__lt=today, order_status="pending"
874
    )
875

876
    # Update their status to 'canceled' and deactivate them
877
    expired_orders.update(order_status="canceled", active=False)
1✔
878

879

880
def get_donations_with_reviews(organization_id):
1✔
881
    """
882
    Fetch donations that have user reviews for a specific organization,
883
    ordered by pickup date with the most recent donations on top.
884
    """
885
    donations_with_reviews = (
1✔
886
        Donation.objects.filter(
887
            organization=organization_id,
888
            userreview__isnull=False,
889
        )
890
        .distinct()
891
        .order_by("-pickup_by")  # Order by pickup date in descending order
892
    )
893
    return donations_with_reviews
1✔
894

895

896
@login_required
1✔
897
def delete_donation_image(request):
1✔
898
    if request.method == "POST":
1✔
899
        donation_id = request.POST.get("donation_id")
1✔
900

901
        if not donation_id:
1✔
902
            return JsonResponse({"success": False, "error": "Invalid data."})
1✔
903

904
        try:
1✔
905
            donation = Donation.objects.get(donation_id=donation_id)
1✔
906
            donation.image_data = None
1✔
907
            donation.save()
1✔
908

909
            return JsonResponse({"success": True})
1✔
910
        except Donation.DoesNotExist:
1✔
911
            return JsonResponse({"success": False, "error": "Donation not found."})
1✔
912
    return JsonResponse({"success": False, "error": "Invalid request method."})
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc