Skip to content

Commit ac5dd42

Browse files
authored
Merge pull request #2 from Ahmad1551/MA-Bots
bots
2 parents e9058ac + 1dd59bd commit ac5dd42

23 files changed

+1152
-31
lines changed

core/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from django.db import models
21
from django.contrib.auth.models import AbstractUser
2+
from django.db import models
33

44
from config.mixins import TimeStampedModel
55
from projects.models import Organization
3.37 KB
Loading

core/static/style.css

+4
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,7 @@ input:focus, select:focus, textarea:focus{
6262
.embed-responsive iframe {
6363
width: 100%;
6464
}
65+
66+
p img {
67+
width: -webkit-fill-available;
68+
}

edu/admin.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from django.contrib import admin
22

3-
from edu.models import Bot, Assignment
3+
from edu.models import Bot, Plan, Subscription, Assignment
44

55
admin.site.register(Bot)
6+
admin.site.register(Plan)
7+
admin.site.register(Subscription)
68
admin.site.register(Assignment)

edu/forms.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from django import forms
22

3+
from core.models import User
34
from edu.models import Bot, Plan, Subscription
5+
from projects.models import Organization
46

57

68
class BotForm(forms.ModelForm):
@@ -22,8 +24,11 @@ class Meta:
2224
fields = '__all__'
2325

2426
def __init__(self, *args, **kwargs):
27+
organization_id = kwargs.pop('organization_id')
2528
super(SubscriptionForm, self).__init__(*args, **kwargs)
2629

30+
self.fields['plan'].queryset = Plan.objects.filter(organization_id=organization_id)
31+
self.fields['user'].queryset = User.objects.filter(organization_id=organization_id)
2732
self.fields['is_active'].widget.attrs['class'] = 'form-check-input'
2833

2934

@@ -33,7 +38,9 @@ class Meta:
3338
fields = '__all__'
3439

3540
def __init__(self, *args, **kwargs):
41+
organization_id = kwargs.pop('organization_id')
3642
super(PlanForm, self).__init__(*args, **kwargs)
3743

44+
self.fields['organization'].queryset = Organization.objects.filter(id=organization_id)
3845
self.fields['is_active'].widget.attrs['class'] = 'form-check-input'
3946
self.fields['is_popular'].widget.attrs['class'] = 'form-check-input'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 4.0.6 on 2022-11-05 17:36
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('edu', '0004_remove_subscription_organization_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='subscription',
15+
name='bot',
16+
),
17+
migrations.AlterField(
18+
model_name='plan',
19+
name='duration',
20+
field=models.IntegerField(blank=True, default=1, help_text='Number of months i.e 1', null=True),
21+
),
22+
]

edu/models.py

+37-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import datetime
2+
13
from django.db import models
24

35
from config.mixins import TimeStampedModel
@@ -22,7 +24,7 @@ class Plan(TimeStampedModel):
2224
name = models.CharField(max_length=255, unique=True)
2325
price = models.DecimalField(max_digits=10, decimal_places=2)
2426
quantity = models.IntegerField(default=1, help_text='Number of Unlocks, Number of Upvotes etc.', blank=True, null=True)
25-
duration = models.IntegerField(default=1, help_text='Number of days, Number of weeks etc.', blank=True, null=True)
27+
duration = models.IntegerField(default=1, help_text='Number of months i.e 1', blank=True, null=True)
2628
description = models.TextField(blank=True, null=True)
2729

2830
is_active = models.BooleanField(default=True)
@@ -33,7 +35,6 @@ def __str__(self):
3335

3436

3537
class Subscription(TimeStampedModel):
36-
bot = models.ForeignKey(Bot, on_delete=models.CASCADE)
3738
user = models.ForeignKey('core.User', on_delete=models.CASCADE)
3839
plan = models.ForeignKey(Plan, on_delete=models.CASCADE)
3940

@@ -42,8 +43,41 @@ class Subscription(TimeStampedModel):
4243
paid_amount = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
4344
is_active = models.BooleanField(default=False)
4445

46+
@property
47+
def is_expired(self):
48+
if self.end_date and self.end_date > datetime.date.today():
49+
return True
50+
return False
51+
52+
@property
53+
def time_left(self):
54+
if self.end_date:
55+
return str(self.end_date - datetime.date.today()).split(',')[0]
56+
return None
57+
58+
@property
59+
def duration_progress(self):
60+
progress = (self.end_date - datetime.date.today()).days * 100 / 30
61+
if progress < 0:
62+
if self.is_expired:
63+
return {'progress': 100, 'class': 'bg-success'}
64+
else:
65+
return {'progress': 100, 'class': 'bg-danger'}
66+
elif progress > 100:
67+
return {'progress': 0, 'class': 'bg-success'}
68+
elif progress < 30:
69+
return {'progress': 100 - progress, 'class': 'bg-danger'}
70+
elif progress < 60:
71+
return {'progress': 100 - progress, 'class': 'bg-success'}
72+
elif progress < 85:
73+
return {'progress': 100 - progress, 'class': 'bg-success'}
74+
elif progress < 100:
75+
return {'progress': 100 - progress, 'class': 'bg-success'}
76+
else:
77+
return {'progress': 0, 'class': 'bg-success'}
78+
4579
def __str__(self):
46-
return f'{self.bot} - {self.organization}'
80+
return self.plan.name
4781

4882

4983
class Assignment(TimeStampedModel):
@@ -60,7 +94,3 @@ class Assignment(TimeStampedModel):
6094

6195
def __str__(self):
6296
return self.name
63-
64-
65-
66-

edu/templates/bartleby_view.html

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
{% extends "common/base.html" %}
2+
3+
{% load static %}
4+
5+
{% block title %}
6+
Dashboard
7+
{% endblock %}
8+
9+
{% block content %}
10+
<div class="row">
11+
<div class="col-12">
12+
<div class="page-title-box">
13+
<h4 class="page-title">Dashboard</h4>
14+
</div>
15+
</div>
16+
</div>
17+
<div class="row">
18+
<div class="col-xxl-9">
19+
<div class="row">
20+
<div class="col-sm-4">
21+
<div class="card tilebox-one">
22+
<div class="card-body">
23+
<i class="ri-shopping-basket-2-line float-end text-muted"></i>
24+
<h6 class="text-muted text-uppercase mt-0">Orders</h6>
25+
<h2 class="m-b-20">1,587</h2>
26+
<span class="badge bg-primary"> +11% </span> <span class="text-muted">From previous period</span>
27+
</div> <!-- end card-body-->
28+
</div> <!--end card-->
29+
</div>
30+
<div class="col-sm-4">
31+
<div class="card tilebox-one">
32+
<div class="card-body">
33+
<i class="ri-shopping-basket-2-line float-end text-muted"></i>
34+
<h6 class="text-muted text-uppercase mt-0">Orders</h6>
35+
<h2 class="m-b-20">1,587</h2>
36+
<span class="badge bg-primary"> +11% </span> <span class="text-muted">From previous period</span>
37+
</div> <!-- end card-body-->
38+
</div> <!--end card-->
39+
</div>
40+
<div class="col-sm-4">
41+
<div class="card tilebox-one">
42+
<div class="card-body">
43+
<i class="ri-shopping-basket-2-line float-end text-muted"></i>
44+
<h6 class="text-muted text-uppercase mt-0">Orders</h6>
45+
<h2 class="m-b-20">1,587</h2>
46+
<span class="badge bg-primary"> +11% </span> <span class="text-muted">From previous period</span>
47+
</div> <!-- end card-body-->
48+
</div> <!--end card-->
49+
</div>
50+
</div>
51+
<div class="row px-2">
52+
<div class="card border border-primary bg-primary card-bg-img" style="background-image: url({% static 'images/bg-pattern-dark.png' %});">
53+
<div class="card-body">
54+
<h5 class="fs-2 text-white text-center">
55+
Discover everything bartleby has to offer
56+
</h5>
57+
<div class="app-search dropdown mt-4 mb-3">
58+
<form action="{% url 'chegg_view' %}" method="post">
59+
{% csrf_token %}
60+
<div class="input-group">
61+
<input type="text" class="form-control dropdown-toggle" placeholder="Find homework solutions, or practice tests" name="chegg-search" id="chegg-search">
62+
<span class="mdi mdi-magnify search-icon"></span>
63+
<input type="submit" class="btn btn-success" value="Submit">
64+
</div>
65+
</form>
66+
</div>
67+
</div>
68+
</div>
69+
<div class="mb-3">
70+
<div class="d-flex justify-content-center">
71+
<div class="col-6">
72+
<div class="alert alert-success alert-dismissible bg-success text-white border-0 fade show mb-0" role="alert">
73+
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
74+
<strong>Success - </strong> A simple success alert—check it out!
75+
</div>
76+
</div>
77+
</div>
78+
</div>
79+
{% if unlock %}
80+
<div class="p-0">
81+
<h3>{{ unlock.questionHead|safe }}</h3>
82+
<div class="card">
83+
<div class="card-body">
84+
<div class="px-3 pt-2">
85+
{{ unlock.question|safe }}
86+
</div>
87+
</div>
88+
</div>
89+
<h3>Expert Answer</h3>
90+
<div class="card">
91+
<div class="card-body">
92+
<div class="row">
93+
<div class="d-flex mt-3">
94+
<a class="pe-2" href="#">
95+
<img src="{% static 'images/chegg/avatar_unisex.png' %}" class="rounded-circle" alt="Generic placeholder image" height="32">
96+
</a>
97+
<div class="w-100">
98+
<h5 class="my-0">{{ unlock.expert }} answered this</h5>
99+
{{ unlock.expertAns }} answers
100+
</div>
101+
</div>
102+
</div>
103+
<div class="p-3 pb-0">
104+
{{ unlock.solution|safe }}
105+
</div>
106+
</div>
107+
</div>
108+
</div>
109+
{% endif %}
110+
</div>
111+
</div>
112+
113+
<div class="col-xxl-3">
114+
{% if subscription.user %}
115+
<div class="row">
116+
<div class="col-md-6 col-xxl-12">
117+
<div class="card border {% if subscription.is_expired == False %}border-primary bg-primary {% else %}border-warning bg-warning{% endif %} card-bg-img" style="background-image: url({% static 'images/bg-pattern.png' %});">
118+
<div class="card-body">
119+
<div class="row">
120+
<h4 class="text-white">
121+
<div class="d-flex align-items-center mt-n1">
122+
<div class="avatar-sm me-1 p-1">
123+
{% if subscription.user.user_image %}
124+
<img src="{{ subscription.user.user_image.url }}" alt="user-image" class="img-fluid rounded-circle">
125+
{% else %}
126+
<span class="avatar-title rounded-circle bg-soft-primary text-white">
127+
{{ subscription.user.user_name }}|make_list|first }}
128+
</span>
129+
{% endif %}
130+
</div>
131+
{{ request.user.get_full_name }}
132+
</div>
133+
</h4>
134+
</div>
135+
136+
<div class="row">
137+
<div class="col-12 d-flex justify-content-center flex-column align-items-center mt-3">
138+
<img src="{{ subscription.plan.bot.image.url }}" alt="image" class="img-fluid avatar-md rounded-circle img-thumbnail">
139+
<h5 class="text-center">{{ subscription.plan.bot.name }}
140+
{% if subscription.plan.bot.is_verified %}
141+
<i class="mdi mdi-check-decagram text-info fs-4"></i>
142+
{% endif %}
143+
</h5>
144+
{% if subscription.plan.bot.is_online %}
145+
<span class="badge badge-success-lighten fw-bold d-flex">
146+
<div class="spinner-grow spinner-grow-sm text-success py-1 my-1" role="status">
147+
</div>
148+
<h6 class="p-1 m-0 d-flex align-items-center">Online</h6>
149+
</span>
150+
{% else %}
151+
<span class="badge badge-danger-lighten fw-bold d-flex">
152+
<div class="spinner-grow spinner-grow-sm text-danger py-1 my-1" role="status">
153+
</div>
154+
<h6 class="p-1 m-0 d-flex align-items-center">Offline</h6>
155+
</span>
156+
{% endif %}
157+
</div>
158+
<div class="col-12 align-items-center d-flex justify-content-between mt-2">
159+
<div class="col-4">
160+
<div class="text-white-50 font-16 mb-1">Access</div>
161+
{% if subscription.is_expired %}
162+
<h5 class="my-0 text-success">
163+
<div class="badge bg-success p-1">Licensed</div>
164+
</h5>
165+
{% else %}
166+
<div class="badge bg-danger p-1">Unlicensed</div>
167+
{% endif %}
168+
</div>
169+
<div class="col-4">
170+
<div class="text-white-50 font-16 mb-1">Expiration Date</div>
171+
<h5 class="text-white my-0 text-end">{{ subscription.end_date }}</h4>
172+
</div>
173+
</div>
174+
<div class="col-12 mt-3">
175+
<div class="d-flex justify-content-between align-items-center">
176+
<h6>License Period</h6>
177+
{% if subscription.is_expired == False %}
178+
<h6>Denied</h6>
179+
{% else %}
180+
<h6>{{ subscription.time_left }} left</h6>
181+
{% endif %}
182+
</div>
183+
<div class="progress" style="height: 5px;">
184+
<div class="progress-bar {{ subscription.duration_progress.class }}" role="progressbar" style="width: {{ subscription.duration_progress.progress }}%; height: 20px;" aria-valuenow="{{ subscription.duration_progress.progress }}" aria-valuemin="0" aria-valuemax="100"></div>
185+
</div>
186+
</div>
187+
</div>
188+
</div>
189+
</div>
190+
</div>
191+
</div>
192+
{% endif %}
193+
<div class="row">
194+
<h5>Serving Bots</h5>
195+
<div class="col-md-6 col-xxl-12">
196+
{% for bot in bots %}
197+
<div class="card border border-primary bg-primary card-bg-img mb-2" style="background-image: url({% static 'images/bg-pattern.png' %});">
198+
<div class="card-body p-2">
199+
<div class="row">
200+
<h4 class="text-white mb-0">
201+
<div class="d-flex align-items-center justify-content-between mt-n1">
202+
<div class="d-flex align-items-center">
203+
<div class="avatar-md me-1 p-1">
204+
<img src="{{ bot.image.url }}" alt="user-image" class="img-fluid rounded-circle img-thumbnail">
205+
</div>
206+
<div class="d-flex flex-column">
207+
<h5 class="mb-0">
208+
{{ bot.name }}
209+
{% if bot.is_verified %}
210+
<i class="mdi mdi-check-decagram text-info fs-4"></i>
211+
{% endif %}
212+
</h5>
213+
{% if bot.is_online %}
214+
<span class="fw-bold d-flex">
215+
<div class="spinner-grow spinner-grow-sm text-success py-1 my-1" role="status">
216+
</div>
217+
<h6 class="p-1 m-0 d-flex align-items-center">Online</h6>
218+
</span>
219+
{% else %}
220+
<span class="fw-bold d-flex">
221+
<div class="spinner-grow spinner-grow-sm text-danger py-1 my-1" role="status">
222+
</div>
223+
<h6 class="p-1 m-0 d-flex align-items-center">Offline</h6>
224+
</span>
225+
{% endif %}
226+
</div>
227+
</div>
228+
<div class="avatar-sm d-table">
229+
<span class="avatar-title bg-info rounded-circle text-white">
230+
<i class="uil uil-link font-24"></i>
231+
</span>
232+
</div>
233+
</div>
234+
</h4>
235+
</div>
236+
</div>
237+
</div>
238+
{% endfor %}
239+
</div>
240+
</div>
241+
</div> <!-- end col -->
242+
</div>
243+
{% endblock %}

0 commit comments

Comments
 (0)