Add IntelliJ IDEA project configuration files

This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.
This commit is contained in:
2025-07-02 11:11:36 +03:00
parent da83ae7afc
commit 0eefaad424
14 changed files with 208 additions and 37 deletions
+40
View File
@@ -1,7 +1,47 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.core.exceptions import ValidationError
from django.forms import CharField
from django.forms.models import ModelForm
from django.forms.widgets import PasswordInput
class LoginForm(AuthenticationForm):
field_order = ['username', 'password']
class Meta:
model = get_user_model()
class RegisterForm(ModelForm):
password1 = CharField(label='Password', widget=PasswordInput)
password2 = CharField(label='Confirm Password', widget=PasswordInput)
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'line', 'company_permissions']
class Meta:
model = get_user_model()
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'line', 'company_permissions']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['password2'].widget.attrs.update({'autocomplete': 'new-password'})
def clean(self):
cleaned_data = super().clean()
password1 = cleaned_data.get('password1')
password2 = cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise ValidationError("Passwords don't match")
return cleaned_data
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
+5 -1
View File
@@ -2,6 +2,9 @@ from django.contrib.auth.models import AbstractUser
from django.db import models
class ClientPermission(models.Model):
codename = models.CharField(max_length=100, default='')
name = models.CharField(max_length=255, default='')
class Meta:
managed = True
default_permissions = ()
@@ -10,7 +13,8 @@ class ClientPermission(models.Model):
('can_view_bookings', 'Can view bookings'),
('can_manage_company_users', 'Can manage company users'),
)
def __str__(self):
return self.name
class DepotUser(AbstractUser):
+1
View File
@@ -5,4 +5,5 @@ from accounts import views
urlpatterns = [
path('login/', views.DepotLoginView.as_view(), name='login'),
path('relogin/', auth_views.logout_then_login, name='relogin'),
path('register/', views.RegisterView.as_view(), name='register'),
]
+26 -2
View File
@@ -1,9 +1,10 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.views import LoginView
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import TemplateView, FormView
from django.views.generic import TemplateView, FormView, ListView, UpdateView
from accounts.forms import LoginForm
from accounts.forms import LoginForm, RegisterForm
# Create your views here.
@@ -14,4 +15,27 @@ class DepotLoginView(LoginView):
next_page = reverse_lazy('dashboard')
class RegisterView(FormView):
template_name = 'registration/register.html'
form_class = RegisterForm
# model = get_user_model()
success_url = reverse_lazy('dashboard')
def form_valid(self, form):
# Create user from form data
user = form.save(commit=False)
# user.set_password(form.cleaned_data['password'])
user.save()
return super().form_valid(form)
class UserListView(ListView):
template_name = 'registration/register.html'
# form_class = RegisterForm
model = get_user_model()
success_url = reverse_lazy('dashboard')
class UserEditView(UpdateView):
template_name = 'registration/register.html'
form_class = RegisterForm
model = get_user_model()
success_url = reverse_lazy('dashboard')
+17 -1
View File
@@ -3,6 +3,13 @@ from common.models import ContainerTypeModel, LinesModel, OperationModel
# Create your models here.
class Booking(models.Model):
STATUS_CHOICES = [
('active', 'Active'),
('finished', 'Finished'),
('canceled', 'Canceled'),
]
number = models.CharField(max_length=50, unique=True)
vehicles = models.CharField(blank=True, null=True)
container_type = models.ForeignKey(
@@ -21,8 +28,17 @@ class Booking(models.Model):
visible = models.BooleanField(default=True)
is_new = models.BooleanField(default=True)
container_number = models.CharField(max_length=11, blank=True, null=True)
vehicles_left = models.IntegerField(blank=True, null=True)
vehicles_left = models.CharField(blank=True, null=True)
created_on = models.DateTimeField(auto_now_add=True)
created_by = models.IntegerField()
updated_on = models.DateTimeField(auto_now=True)
updated_by = models.IntegerField()
status = models.CharField(
max_length=10,
choices=STATUS_CHOICES,
default='active'
)
@property
def containers_left(self):
return self.container_count - (self.container_expedited_count or 0)
+12 -2
View File
@@ -12,7 +12,7 @@ class CreateBookingView(CreateView):
template_name = 'client-booking-content.html'
model = Booking
form_class = BookingCreateForm
success_url = reverse_lazy('dashboard')
success_url = reverse_lazy('client_booking')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@@ -21,15 +21,25 @@ class CreateBookingView(CreateView):
# !!! important
queryset = filter_queryset_by_user( queryset, user)[:10]
# !!! important
context['recent'] = queryset
return context
def get_form(self, form_class=None):
form = super().get_form(form_class)
user = self.request.user
# If user has a specific line, limit the line choices
if user.line:
form.fields['line'].queryset = form.fields['line'].queryset.filter(pk=user.line.pk)
form.fields['line'].initial = user.line
form.fields['line'].widget.readonly = True #attrs['disabled'] = True
return form
def form_valid(self, form):
# todo more validation
form.instance.created_by = self.request.user.id
form.instance.updated_by = self.request.user.id
form.instance.vehicles_left = form.cleaned_data.get('vehicles')
if self.request.user.line:
form.instance.line = self.request.user.line
return super().form_valid(form)
+1 -1
View File
@@ -39,7 +39,7 @@ class ClientPreinfoView(LoginRequiredMixin, CreateView):
if user.line:
form.fields['line'].queryset = form.fields['line'].queryset.filter(pk=user.line.pk)
form.fields['line'].initial = user.line
form.fields['line'].widget.attrs['disabled'] = True
form.fields['line'].widget.readonly = True #form.fields['line'].widget.attrs['disabled'] = True
# Keep the value when form is submitted
# form.fields['line'].widget = HiddenInput()
+29 -20
View File
@@ -59,7 +59,14 @@
</head>
<body>
{% load static %}
<div class="sidebar w-64 h-full text-white flex flex-col">
<div class="sidebar p-5 text-white border-b border-blue-700">
<h1 class="text-xl font-bold">Container Depot</h1>
<p class="text-sm text-blue-200">Line Operator Portal</p>
</div>
<div class="flex min-h-screen items-center justify-center">
<div class="sidebar w-[400px] h-[600px] text-white flex flex-col rounded-lg overflow-hidden">
<div class="sidebar w-[100%] h-full text-white flex flex-col">
<div class="p-5 border-b border-blue-700">
<h1 class="text-xl font-bold">Container Depot</h1>
<p class="text-sm text-blue-200">Line Operator Portal</p>
@@ -67,19 +74,19 @@
<nav class="flex-grow py-4">
<div class="px-4 py-2 text-xs text-blue-300 uppercase tracking-wider">Main</div>
<a href="{% url 'barrier_dashboard' %}" class="nav-item active flex items-center px-6 py-3 text-white">
<a href="{% url 'barrier_dashboard' %}" class="nav-item active flex items-center px-6 py-10 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
Dashboard
</a>
<a href="{% url 'preinfo_search' %}?param=container_receive" id="ordersNav" class="nav-item flex items-center px-6 py-3 text-white">
<a href="{% url 'preinfo_search' %}?param=container_receive" id="ordersNav" class="nav-item flex items-center px-6 py-10 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Receive container
</a>
<a href="{% url 'container_search' %}?param=container_expedition" id="ordersNav" class="nav-item flex items-center px-6 py-3 text-white">
<a href="{% url 'container_search' %}?param=container_expedition" id="ordersNav" class="nav-item flex items-center px-6 py-10 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
@@ -92,7 +99,7 @@
Photos
</a>
<div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>
{# <div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>#}
{# <a href="#" class="nav-item flex items-center px-6 py-3 text-white">#}
{# <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">#}
{# <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />#}
@@ -102,23 +109,25 @@
{# </a>#}
</nav>
<div class="p-4 border-t border-blue-700">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">
LO
{# <div class="p-4 border-t border-blue-700">#}
{# <div class="flex items-center">#}
{# <div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">#}
{# LO#}
{# </div>#}
{# <div class="ml-3">#}
{# <p class="text-sm font-medium">Maersk Line</p>#}
{# <p class="text-xs text-blue-300">Line Operator</p>#}
{# </div>#}
{# <button class="ml-auto text-white">#}
{# <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">#}
{# <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />#}
{# </svg>#}
{# </button>#}
{# </div>#}
{# </div>#}
</div>
<div class="ml-3">
<p class="text-sm font-medium">Maersk Line</p>
<p class="text-xs text-blue-300">Line Operator</p>
</div>
<button class="ml-auto text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
</button>
<div class="flex-grow"></div>
</div>
</div>
</div>
</body>
</html>
+5 -3
View File
@@ -4,8 +4,8 @@
<div id="preinfoContent" class="tab-content active">
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Submit Container Preinfo</h3>
<p class="text-sm text-gray-600 mt-1">Provide information about containers that will arrive at the depot</p>
<h3 class="text-lg font-semibold text-gray-800">Submit Booking</h3>
<p class="text-sm text-gray-600 mt-1">Create a booking for containers expedition by container type or by specific container numer</p>
</div>
<div class="p-6">
<form id="preinfoForm" class="space-y-6" method="POST" >
@@ -35,6 +35,7 @@
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container №</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container count</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Containers left</th>
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicles</th>#}
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicles</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
@@ -48,10 +49,11 @@
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">{{ booking.container_number }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_type }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_count }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.containers_left }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.vehicles_left }}</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">Pending</span>
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">{{ booking.status }}</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">
<button class="text-blue-600 hover:text-blue-800 mr-3">Edit</button>
+1 -1
View File
@@ -41,7 +41,7 @@
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Pending Orders</h3>
<h3 class="text-lg font-semibold text-gray-700">Bookings</h3>
<p class="text-3xl font-bold text-gray-900">7</p>
<p class="text-sm text-orange-600">2 require attention</p>
</div>
+1 -1
View File
@@ -23,7 +23,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Expedition Orders
Bookings
</a>
<a href="#" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+7 -2
View File
@@ -5,7 +5,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>K-DepoT | Kikimor EOOD</title>
<title>
K-DepoT | Kikimor EOOD</title>
<style>
body {
font-family: Arial, sans-serif;
@@ -89,7 +91,10 @@ header {
<header>
<div class="header-content">
<h1>K-DepoT</h1>
<h1>
<img src="{% static 'images/k-depot-logo.svg' %}" alt="K-DepoT Logo" style="height: 150px; vertical-align: middle;">
K-DepoT
</h1>
<p>Operated by Kikimor EOOD</p>
</div>
<a href="{% url 'login' %}" class="login-link">Login</a>
+46
View File
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<video id="video" autoplay></video>
<canvas id="canvas" style="display:none;"></canvas>
<button onclick="takePhoto()">Take Photo</button>
<script>
const video = document.getElementById('video');
// Request camera access
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => video.srcObject = stream)
.catch(err => console.error("Camera access denied", err));
function takePhoto() {
const canvas = document.getElementById('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
// Draw current frame
const context = canvas.getContext('2d');
context.drawImage(video, 0, 0);
// Convert to base64 or Blob
canvas.toBlob(blob => {
// Upload blob to server
const formData = new FormData();
formData.append("photo", blob, "photo.jpg");
fetch("https://your-upload-url.com/upload", {
method: "POST",
body: formData
}).then(res => console.log("Uploaded"))
.catch(err => console.error("Upload failed", err));
}, "image/jpeg");
}
</script>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Register User</title>
</head>
<body>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Register</button>
</form>
</body>
</html>