oleg-test README
failed to load extension from chrome
failed to load extension from manifest file is missing or unreadable
failed to load extensions from file microsoft.visualstudio.testplatform.mstest.testadapter.dll
failed to load extension webgl is not supported
failed to load extension no response was received to the core_enumextcmd request
Issues addressed in this tutorial:
failed to load extension from chrome
failed to load extension from manifest file is missing or unreadable
failed to load extensions from file microsoft.visualstudio.testplatform.mstest.testadapter.dll
failed to load extension webgl is not supported
failed to load extension no response was received to the core_enumextcmd request
Issues addressed in this tutorial:
failed to load extension from chrome
failed to load extension from manifest file is missing or unreadable
failed to load extensions from file microsoft.visualstudio.testplatform.mstest.testadapter.dll
failed to load extension webgl is not supported
failed to load extension no response was received to the core_enumextcmd request
failed to load extension no response was received to the core_enumextcmd request
Issues addressed in this tutorial:
failed to load extension from chrome
failed to load extension from manifest file is missing or unreadable
failed to load extensions from file microsoft.visualstudio.testplatform.mstest.testadapter.dll
failed to load extension webgl is not supported
failed to load extension no response was received to the core_enumextcmd request
views.py (module1/shop/)
from rest_framework.generics import RetrieveUpdateDestroyAPIView, CreateAPIView, ListAPIView, DestroyAPIView, ListCreateAPIView
from django.http import Http404, JsonResponse
from rest_framework.views import APIView
from .serializers import *
from .models import *
from rest_framework.authtoken.models import Token
from rest_framework import exceptions
from .renderers import *
from rest_framework import viewsets
from rest_framework.permissions import IsAdminUser, IsAuthenticated
class ProductsListView(ListAPIView):
serializer_class = ProductsSerializer
renderer_classes = [ProductsRenderer]
queryset = Product.objects.all()
class ProductsDeleteUpdateView(RetrieveUpdateDestroyAPIView):
serializer_class = ProductsSerializer
renderer_classes = [ProductsRenderer]
permission_classes = [IsAdminUser]
queryset = Product.objects.all()
class ProductsCreateView(CreateAPIView):
serializer_class = ProductsSerializer
renderer_classes = [ProductsRenderer]
permission_classes = [IsAdminUser]
queryset = Product.objects.all()
class Signup(APIView):
def post(self, *args, **kwargs):
serializer = UserSerializer(data = self.request.data)
if serializer.is_valid():
user = CustomUser.objects.create(**serializer.validated_data)
user.set_password(serializer.validated_data["password"])
user.save()
token = Token.objects.create(user=user)
return JsonResponse({"data" : {"user_token" : token.key}}, status=201)
return JsonResponse({"error" : {"code" : 422, "message" : "Validation errors", "errors" : serializer.errors}})
class Login(APIView):
def post(self, *args, **kwargs):
serializer = LoginSerializer(data = self.request.data)
if serializer.is_valid():
user = CustomUser.objects.filter(email = self.request.data["email"]).first()
if not user or not user.check_password(self.request.data["password"]):
return JsonResponse({"error" : {"code" : 401, "message" : "Authentication failed"}}, status=401)
token, created = Token.objects.get_or_create(user=user)
return JsonResponse({"data" : {"user_token" : token.key}}, status=201)
return JsonResponse({"error" : {"code" : 422, "message" : "Validation errors", "errors" : serializer.errors}})
class Logout(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
request.user.auth_token.delete()
return JsonResponse({"data" : {"message" : "Logout"}}, status=201)
class CartListView(ListAPIView):
serializer_class = CartGetSerializer
permission_classes = [IsAuthenticated]
renderer_classes = [CartRenderer]
def get_queryset(self, *args, **kwargs):
return Cart.objects.filter(user=self.request.user)
class CartCreateDeleteView(CreateAPIView, DestroyAPIView):
serializer_class = CartSerializer
permission_classes = [IsAuthenticated]
renderer_classes = [CartRenderer]
def get_queryset(self):
return Cart.objects.filter(user=self.request.user)
def post(self, request, *arg, **kwargs):
product_to_add = Product.objects.filter(id = kwargs["pk"]).first()
if not product_to_add:
raise Http404
request.data["user"] = request.user.id
request.data["product"] = product_to_add.id
return self.create(request, *arg, **kwargs)
def delete(self, request, *arg, **kwargs):
cart_to_delete = Cart.objects.filter(id = kwargs["pk"]).first()
if not cart_to_delete:
raise Http404
elif cart_to_delete.user != request.user:
raise exceptions.PermissionDenied
return self.destroy(request, *arg, **kwargs)
class OrderListCreateView(ListCreateAPIView):
serializer_class = OrderSerializer
permission_classes = [IsAuthenticated]
renderer_classes = [OrderRenderer]
def get_queryset(self):
return Order.objects.filter(user=self.request.user)
def post(self, request):
current_cart = Cart.objects.filter(user=request.user)
if not current_cart:
return JsonResponse({"error" : {"message" : "Cart is empty"}}, status=422)
order_price = 0
products = []
for cart in current_cart:
order_price += cart.product.price
products.append(cart.product.id)
request.data["user"] = request.user.id
request.data["products"] = str(products)
request.data["order_price"] = order_price
current_cart.delete()
return self.create(request)
utils.py (module1/shop/)
from django.http import Http404, JsonResponse
def custom_exeption_handler(exc, context=None):
if type(exc) == Http404:
return JsonResponse({"error" : {"code" : 404, "message" : "Not found"}}, status=404)
if exc.default_code == "not_authenticated" or exc.default_code == "authentication_failed":
return JsonResponse({"error" : {"code" : 403, "message" : "Login failed"}}, status=403)
if exc.default_code == "permission_denied":
return JsonResponse({"error" : {"code" : 403, "message" : "Forbidden for you"}}, status=403)
if exc.default_code == "invalid":
return JsonResponse({"error" : {"code" : 422, "message" : "Validations errors", "errors" : exc.detail}}, status=422)
urls.py (module1/shop/)
from math import fabs
from rest_framework import routers
from django.urls import path, include
from .views import *
urlpatterns = [
path('signup', Signup.as_view()),
path('login', Login.as_view()),
path('logout', Logout.as_view()),
path('cart', CartListView.as_view()),
path('order', OrderListCreateView.as_view()),
path('cart/<int:pk>', CartCreateDeleteView.as_view()),
path('products', ProductsListView.as_view()),
path('product', ProductsCreateView.as_view()),
path('product/<int:pk>', ProductsDeleteUpdateView.as_view())
]
serializers.py (module1/shop/)
from rest_framework import serializers
from .models import *
class ProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = "__all__"
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField()
class CartGetSerializer(serializers.ModelSerializer):
product_id = serializers.IntegerField(source='product.id')
name = serializers.CharField(source='product.title')
description = serializers.CharField(source='product.description')
price = serializers.IntegerField(source='product.price')
class Meta:
model = CustomUser
fields = ("id", "product_id", "name", "description", "price")
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = Cart
fields = "__all__"
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = ("id", "user", "products", "order_price")
renderers.py (module1/shop/)
from rest_framework.renderers import JSONRenderer
class ProductsRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, render_context=None):
if render_context['request'].method == 'GET':
response = {"data" : data}
if render_context['request'].method == 'POST':
response = {"data" : {"id" : data['id'], "message" : "Product added"}}
if render_context['request'].method == 'PATCH':
response = {"data" : data}
if render_context['request'].method == 'DELETE':
response = {"data" : {"message" : "Product removed"}}
return super(ProductsRenderer, self).render(response, accepted_media_type, render_context)
class CartRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, render_context=None):
if render_context['request'].method == 'GET':
response = {"data" : data}
if render_context['request'].method == 'POST':
response = {"data" : {"message" : "Product added to cart"}}
if render_context['request'].method == 'DELETE':
response = {"data" : {"message" : "Item removed from cart"}}
return super(CartRenderer, self).render(response, accepted_media_type, render_context)
class OrderRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, render_context=None):
if render_context['request'].method == 'GET':
for order in data:
del order["user"]
order["products"] = [int(i) for i in order["products"][1:-1].split(", ")]
response = {"data" : data}
if render_context['request'].method == 'POST':
response = {"data" : {"id" : data['id'], "message" : "Order in procces"}}
return super(OrderRenderer, self).render(response, accepted_media_type, render_context)
models.py (module1/shop/)
from array import array
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.core.validators import MinLengthValidator
class Product(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
price = models.IntegerField()
class CustomUser(AbstractUser):
username = ''
fio = models.CharField(max_length=255)
email = models.EmailField(unique=True)
password = models.CharField(max_length=255, validators=[MinLengthValidator(6)])
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
class Cart(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
class Order(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
products = models.TextField(array)
order_price = models.IntegerField()
authentication.py (module1/shop/)
from rest_framework.authentication import TokenAuthentication
class BearerAuthentication(TokenAuthentication):
keyword = 'Bearer'
settings.py (module1/mysite/)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'shop',
'rest_framework',
'rest_framework.authtoken',
]
AUTH_USER_MODEL = 'shop.CustomUser'
REST_FRAMEWORK = {
"EXCEPTION_HANDLER" : 'shop.utils.custom_exeption_handler',
"DEFAULT_AUTHENTICATION_CLASSES" : (
'shop.authentication.BearerAuthentication',
)
}
module2
index.js
const HashRouter = window.ReactRouterDOM.HashRouter;
const Route = window.ReactRouterDOM.Route;
const Link = window.ReactRouterDOM.Link;
class Page extends React.Component {
render() {
return (
<div class='pricing-header p-3 pb-md-4 mx-auto text-center'>
<h1 class='display-4 fw-normal'>{this.props.name}</h1>
</div>
);
}
}
class Product extends React.Component {
constructor(props) {
super(props);
this.state = {
products: [],
};
}
componentDidMount() {
fetch("http://shop.api.deadzeta.ru/api-shop/products")
.then((res) => res.json())
.then((result) => {
this.setState({
products: result.data,
});
});
}
Add(id) {
fetch("http://shop.api.deadzeta.ru/api-shop/cart/" + id, {
method: "POST",
headers: {
Authorization: "Bearer " + localStorage.getItem("user_token"),
},
});
}
render() {
const { products } = this.state;
return (
<div class='products row row-cols-1 row-cols-md-3 mb-3 text-center'>
{products.map((product) => (
<div class='col'>
<div class='card mb-4 rounded-3 shadow-sm'>
<div class='card-header py-3'>
<h4 class='my-0 fw-normal'>{product.name}</h4>
</div>{" "}
{/*ВЕРСТКА ГЛАВНОЙ СТРАНИЦЫ*/}
<div class='card-body'>
<h1 class='card-title pricing-card-title'>
{product.price} руб.
</h1>
<p>{product.description}</p>
<button
onClick={() => this.Add(product.id)}
type='button'
class='w-100 btn btn-lg btn-outline-primary'
>
Добавить в корзину
</button>
</div>
</div>
</div> // /
))}
</div> // /
);
}
}
class Login extends React.Component {
async onSubmit(ev) {
ev.preventDefault();
console.log(localStorage.getItem("user_token"))
let response = null;
try {
response = await fetch("http://shop.api.deadzeta.ru/api-shop/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: ev.target.elements.email.value,
password: ev.target.elements.password.value,
}),
});
} catch (error) {
return;
}
const result = await response.json()
console.log(result.data.user_token)
localStorage.setItem("user_token", result.data.user_token)
}
render() {
return(
<div class="row row-cols-1 row-cols-md-3 mb-3 text-center justify-content-center">
<div class="col">
<div class="row">
<form onSubmit={(ev) => this.onSubmit(ev)}>
<div class="form-floating mb-3">
<input name="email" type="email" class="form-control" id="floatingInput" placeholder="name@example.com" />
<label for="floatingInput">Email</label>
</div>
<div class="form-floating mb-3">
<input name="password" type="password" class="form-control" id="floatingPassword" placeholder="Password" />
<label for="floatingPassword">Password</label>
</div>
<button class="w-100 btn btn-lg btn-primary mb-3" type="submit">Войти</button>
<button class="w-100 btn btn-lg btn-outline-info" type="submit">Назад</button>
</form>
</div>
</div>
</div>
)
}
}
class Registration extends React.Component {
async onSubmit(ev) {
ev.preventDefault();
let response = null;
try {
response = await fetch("http://shop.api.deadzeta.ru/api-shop/signup", {
method: "POST",
body: JSON.stringify({
email: ev.target.elements.email.value,
password: ev.target.elements.password.value,
fio: ev.target.elements.fio.value,
}),
headers: {
"Content-Type": "application/json",
},
});
} catch (error) {
console.log(response);
}
}
render() {
return (
<div class='row row-cols-1 row-cols-md-3 mb-3 text-center justify-content-center'>
<div class='col'>
<div class='row'>
<form onSubmit={(ev) => this.onSubmit(ev)}>
<h1 class='h3 mb-3 fw-normal'>Пожалуйста заполните все поля</h1>
<div class='form-floating mb-3'>
<input
name='fio'
type='text'
class='form-control'
id='floatingFio'
placeholder='ФИО'
/>
<label for='floatingFio'>ФИО</label>
</div>
<div class='form-floating mb-3'>
<input
name='email'
type='email'
class='form-control'
id='floatingInput'
placeholder='name@example.com'
/>
<label for='floatingInput'>Email</label>
</div>
<div class='form-floating mb-3'>
<input
name='password'
type='password'
class='form-control'
id='floatingPassword'
placeholder='Password'
/>
<label for='floatingPassword'>Password</label>
</div>
<button class='w-100 btn btn-lg btn-primary mb-3' type='submit'>
Зарегистрироваться
</button>
<button class='w-100 btn btn-lg btn-outline-info' type='submit'>
Назад
</button>
</form>
</div>
</div>
</div>
);
}
}
const Header = () => {
async function Logout() {
fetch("http://shop.api.deadzeta.ru/api-shop/logout", {
headers: {
"Authorization": "Bearer " + localStorage.getItem("user_token")
}
})
localStorage.removeItem("user_token")
}
return (
<div class="d-flex flex-column flex-md-row align-items-center pb-3 mb-4 border-bottom">
<CustomAnimation to="/" class="d-flex align-items-center text-dark text-decoration-none">
<span class="fs-4">«Just buy»</span>
</CustomAnimation>
<nav class="d-inline-flex mt-2 mt-md-0 ms-md-auto">
<CustomAnimation to='/registration' class="me-3 py-2 text-dark text-decoration-none">Регистрация</CustomAnimation>
<CustomAnimation to='/login' class="me-3 py-2 text-dark text-decoration-none">Авторизация</CustomAnimation>
<CustomAnimation to='/order' class="me-3 py-2 text-dark text-decoration-none">Мои заказы</CustomAnimation>
<CustomAnimation to='/cart' class="me-3 py-2 text-dark text-decoration-none">Корзина</CustomAnimation>
<CustomAnimation>
<a onClick={Logout()} to='/cart' class="me-3 py-2 text-dark text-decoration-none">Выйти</a>
</CustomAnimation>
</nav>
</div>
)
}
class Cart extends React.Component {
constructor(props) {
super(props);
this.state = {
products: []
}
}
componentDidMount() {
fetch('http://shop.api.deadzeta.ru/api-shop/cart', {
headers: {
"Authorization": "Bearer " + localStorage.getItem("user_token")
}
}).then(res => res.json()).then((result) => {
this.setState({
products: result.data
})
})
}
render() {
async function deleteFromCart(id) {
fetch(`http://shop.api.deadzeta.ru/api-shop/cart/${id}`, {
method: "DELETE",
headers: {
"Authorization": "Bearer " + localStorage.getItem("user_token")
}
})
}
async function Ordering() {
fetch('http://shop.api.deadzeta.ru/api-shop/order', {
method: "POST",
headers: {
"Authorization": "Bearer " + localStorage.getItem("user_token")
}
})
}
const { products } = this.state
return(
<>
<div class="row row-cols-1 row-cols-md-3 mb-3 text-center">
{products.map(product => (
<div class="col">
<div class="card mb-4 rounded-3 shadow-sm">
<div class="card-header py-3">
<h4 class="my-0 fw-normal">{product.name}</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">{product.price}<small class="text-muted fw-light"> × 1
шт.</small></h1>
<p>{product.description}</p>
<button type="button" class="btn btn-lg btn-info mb-3">+</button>
<button type="button" class="btn btn-lg btn-warning mb-3">−</button>
<button onClick={() => deleteFromCart(product.id).then(this.setState(this.componentDidMount))} type="button" class="btn btn-lg btn-outline-danger mb-3">Удалить из корзины</button>
</div>
</div>
</div>
))}
<div>
<div class="row justify-content-center gap-1">
<h2 class="mb-5">Итоговая стоимость: {products.reduce((total, { price }) => price + total, 0)}р.</h2>
<CustomAnimation to='/' class="col-6 btn btn-lg btn-outline-info mb-3" type="button">Назад</CustomAnimation>
<button onClick={() => Ordering().then(this.setState(this.componentDidMount))} type="button" class="col-6 btn btn-lg btn-primary mb-3">Оформить заказ</button>
</div>
</div>
</div>
</>
)
}
}
class Order extends React.Component {
constructor(props) {
super(props);
this.state = {
products: []
}
}
componentDidMount() {
fetch("http://shop.api.deadzeta.ru/api-shop/order", {
headers: {
"Authorization": "Bearer " + localStorage.getItem("user_token")
}
}).then(res => res.json()).then((result) => {
this.setState({
products: result.data
})
})
}
render() {
const { products } = this.state
return(
<div>
{products.map(product => (
<div class="row row-cols-1 row-cols-md-3 mb-3 text-center bg-light">
<h2 class="w-100">Заказ №{products.id}</h2>
<div class="col">
<div class="card mb-4 rounded-3 shadow-sm">
<div class="card-header py-3">
<h4 class="my-0 fw-normal">Название товара</h4>
</div>
<div class="card-body">
<h1 class="card-title pricing-card-title">{product.order_price}руб.<small class="text-muted fw-light"> × 2 шт.</small></h1>
<p>{product.description}</p>
</div>
</div>
</div>
</div>
))}
<div>
<div class="row justify-content-center gap-1">
<h2 class="mb-5">Итоговая стоимость: {products.reduce((total, { order_price }) => order_price + total, 0)}р.</h2>
<CustomAnimation to='/' class="col-6 btn btn-lg btn-outline-info mb-3" type="button">Назад</CustomAnimation>
</div>
</div>
</div>
)
}
}
class Main extends React.Component {
render() {
return (
<HashRouter>
<Header />
<main id="main">
<Route exact path='/'>
<Page name='Каталог Товаров' />
<Product />
</Route>
<Route path='/login'>
<Page name='Авторизация' />
<Login />
</Route>
<Route path="/cart">
<Page name="Корзина" />
<Cart />
</Route>
<Route path="/order">
<Page name="Мои заказы" />
<Order />
</Route>
<Route path='/registration'>
<Page name='Регистрация' />
<Registration />
</Route>
</main>
</HashRouter>
);
}
}
ReactDOM.render(<Main />, document.getElementById("root"));
index.html
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/animation.css">
<title>«Just buy»</title>
<script src="./React/babel.min.js"></script>
<script src="./React/react.development.js"></script>
<script src="./React/react-dom.development.js"></script>
<script src="./React/react-router-dom.min.js"></script>
</head>
<body>
<div id="root" class="container py-3"></div>
<script type="text/babel" src="./Components/CustomAnimation.js" crossorigin></script>
<script type="text/babel" src="index.js" crossorigin></script>
</body>
</html>
animation.css
main {
opacity: 1;
transform: translate(0, 0);
filter: blur(0);
transition: all 1s;
}
.hide {
opacity: 0;
transform: translate(-300px, 0);
filter: blur(10px);
}
CustomAnimation.js
let animationTimeout = 0;
window.CustomAnimation = (props) => {
const history = window.ReactRouterDOM.useHistory();
return (
<a href={`#${props.to}`}
{...props}
onClick={(ev) => {
ev.preventDefault();
document.getElementById("main").classList.add("hide");
clearTimeout(animationTimeout);
animationTimeout = setTimeout(() => {
history.push(props.to);
document.getElementById("main").classList.remove("hide");
}, 500)
}}
/>
)
}