l="diff-a5cc2925ca8258af241be7e5b0381edf30266302R151">151
+
152
+# End of https://www.toptal.com/developers/gitignore/api/django
153
+data/
154
+media/

+ 3 - 0
.vscode/settings.json

@@ -0,0 +1,3 @@
1
+{
2
+    "python.formatting.provider": "yapf"
3
+}

BIN
071e1563b7c24e91a42ede26fff49a8d.png


+ 11 - 0
Dockerfile

@@ -0,0 +1,11 @@
1
+# syntax=docker/dockerfile:1
2
+FROM python:3
3
+ENV PYTHONUNBUFFERED=1
4
+ADD ./app /code
5
+WORKDIR /code
6
+RUN apt-get update && apt-get install -y \
7
+        gettext \
8
+        xfonts-thai \
9
+        gdal-bin libgdal-dev python3-gdal binutils libproj-dev \
10
+        stunnel
11
+RUN pip install -r requirements.txt

+ 26 - 0
app/cert.pem

@@ -0,0 +1,26 @@
1
+-----BEGIN CERTIFICATE-----
2
+MIIEdTCCAt2gAwIBAgIQHZxX+6y4OViy/tCHkaIX+jANBgkqhkiG9w0BAQsFADCB
3
+kTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTMwMQYDVQQLDCpzaW1w
4
+bGljb2x0ZC5AbWFjaGluZS5sb2NhbCAoU2ltcGxpY28gTHRkLikxOjA4BgNVBAMM
5
+MW1rY2VydCBzaW1wbGljb2x0ZC5AbWFjaGluZS5sb2NhbCAoU2ltcGxpY28gTHRk
6
+LikwHhcNMjEwNzI0MTAzMjUzWhcNMjMxMDI0MTAzMjUzWjBdMScwJQYDVQQKEx5t
7
+a2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxMjAwBgNVBAsMKXJvb3RAbWFj
8
+aGluZS5sb2NhbCAoU3lzdGVtIEFkbWluaXN0cmF0b3IpMIIBIjANBgkqhkiG9w0B
9
+AQEFAAOCAQ8AMIIBCgKCAQEAzO3kDm8SonO2P/pSOQmFPYoj2+fz8nEd5ss+vL/e
10
+Rc5BaJsq1651glIdOyUX13B4E0viTF0aa6SP9jZLU6lPluJwW5UYCuVSW67wL0Ev
11
+C82TBpBz2hMGuC6DcpG0nJgzY04kuz0mJaqWtWD4AMq3BOwgBNy2PrB45cUGBBe3
12
+bvsCip9ykVW8vHEWKgHpdnZvUYnbbbea9jDR/nB0cDeKd5K45V/Lv2ECBAGa272C
13
+9a9uqXuzIcVFsdOb9ss6YNyiSs1AJeXTV16M5u6ZlVN95IU9AHqWxeTCVYyGZWZt
14
+g1XD7MB/M22/mDUjZg1fdK3v2n+RFxyo/FGoNE6ziACz6wIDAQABo3wwejAOBgNV
15
+HQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYDVR0jBBgwFoAUHmGB
16
+OP5O8TsFjAThvXx+jAsNHWQwMgYDVR0RBCswKYIJbG9jYWxob3N0hwQAAAAAhwR/
17
+AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBgQA/wteJRFk9
18
+0NqaOKrD1YPXvhq+rXns5yEWgnomi11d5LkHvwtM9A9HmkW0/LB8FPoiY17NUPqR
19
+xZi2RAQcHn9j1wDuBKEMb5Y/xCt5k+Szhyvgfxyqkt4ef4yJ46vIcSXTLjb/+LWm
20
+LW+YLl4vbtYnq4zYtcczVQrnDoPNZGjTGIGDs15PzHZoFt7fY7dypFr/McZnI11z
21
+RRd+z7cjMoxs9UCO7O/f/E8Rpv6pkNuAVzPrezy84fcyN9elbr1eJVNKjLXWf0CR
22
+Ry2PxLkK/x7tWcE2eLVY+kZC5HfHzkiXgulBazhXprLwIcFwePmkQQ2b8ktY/+io
23
+a5DUZ56gZV2BpLK0KiokAmRZh5GWBkMwrJu5YgALiqJAGGg+JBPC6SMOp9vlXPqw
24
+zldZGjtb8jcFpCC6xMvsWag+MF6pIQrOSV+AaPf5/008jbrfwDlBXtMcxWmNtBJv
25
+CAFZlQ+UNIb/QHEM22WQNGacCmyX+hLy/GwCJVk8wyNfPOz2wYKVeAk=
26
+-----END CERTIFICATE-----

BIN
app/client.ks


+ 0 - 0
app/front/__init__.py


+ 3 - 0
app/front/admin.py

@@ -0,0 +1,3 @@
1
+from django.contrib import admin
2
+
3
+# Register your models here.

+ 6 - 0
app/front/apps.py

@@ -0,0 +1,6 @@
1
+from django.apps import AppConfig
2
+
3
+
4
+class FrontConfig(AppConfig):
5
+    default_auto_field = 'django.db.models.BigAutoField'
6
+    name = 'front'

+ 0 - 0
app/front/migrations/__init__.py


+ 3 - 0
app/front/models.py

@@ -0,0 +1,3 @@
1
+from django.db import models
2
+
3
+# Create your models here.

+ 13 - 0
app/front/templates/front/_grids.html

@@ -0,0 +1,13 @@
1
+<div class="row">
2
+    {% for o in objs %}
3
+    <div class="col-md-3">
4
+        {% if o.featureImage %}
5
+        <img src='{{ o.featureImage.url }}'>
6
+        {% endif %}
7
+        {{ o.name }}
8
+    </div>
9
+    {% endfor %}
10
+</div >
11
+
12
+
13
+

+ 0 - 0
app/front/templates/front/_localSearch.html


+ 49 - 0
app/front/templates/front/_menu.html

@@ -0,0 +1,49 @@
1
+{% load mptt_tags %}
2
+<header class="blog-header py-3">
3
+	<div class="row flex-nowrap justify-content-between align-items-center">
4
+		<div class="col-2 pt-1">
5
+			<a class="text-muted" href="#">Subscribe</a>
6
+		</div>
7
+		<div class="col-6 text-center">
8
+			<a class="blog-header-logo text-dark" href="{% url "front:index" %}">SimpleMarket
9
+          {% if storeFront %}
10
+            :{{ storeFront.fullName }}
11
+          {% endif %}
12
+      </a>
13
+		</div>
14
+		<div class="col-4 d-flex justify-content-end align-items-center">
15
+        <form class="form-inline mt-2 mt-md-0" action="{% url "front:search" %}" method="GET">
16
+            {% if storeFront %}
17
+            <input type="hidden" name='cstr' value='{{ storeFront.storeId }}' />
18
+            {% endif %}
19
+            <input class="form-control form-control-sm  mr-sm-2" type="text" placeholder="Search" aria-label="Search" name='q'>
20
+            <button class="btn  btn-sm btn-outline-success my-2 my-sm-0" type="submit">Search</button>
21
+        </form>
22
+            {% if user.is_authenticated %}
23
+            <a class="ml-2 btn btn-sm btn-outline-secondary" href="{% url "logout" %}">Sign Out</a>
24
+            {% else  %}
25
+            <a class="btn btn-sm btn-outline-secondary mx-2" href="{% url "login" %}">Sign In</a>
26
+            {% endif %}
27
+		</div>
28
+	</div>
29
+</header>
30
+
31
+<div class="nav-scroller py-1 mb-2">
32
+	<nav class="nav d-flex justify-content-between">
33
+		
34
+      <!--<a class="p-2 text-muted" href="#">Home</a>-->
35
+		<!--<a class="p-2 text-muted" href="#">News</a>-->
36
+        <!--<a class="p-2 text-muted" href="#">Market</a>-->
37
+		<!--<a class="p-2 text-muted" href="#">Articles</a>-->
38
+		<!--<a class="p-2 text-muted" href="#">Forum</a>-->
39
+    {% recursetree primaryMenu %}
40
+    {% if node.name != "root" %}
41
+    <a class="p-2 text-muted" href="{{ node.url }}">{{ node.name }}</a>
42
+    {% endif %}
43
+    {{ children }}
44
+    {% endrecursetree %}
45
+	</nav>
46
+</div>
47
+
48
+<hr>
49
+

+ 14 - 0
app/front/templates/front/_menu_ui.html

@@ -0,0 +1,14 @@
1
+{% load mptt_tags %}
2
+<ul>
3
+    {% recursetree menu %}
4
+        <li>
5
+            <a href="{{ node.url | safe }}">{{ node.name }}</a>
6
+            {% if not node.is_leaf_node %}
7
+                <ul class="children">
8
+                    {{ children }}
9
+                </ul>
10
+            {% endif %}
11
+        </li>
12
+    {% endrecursetree %}
13
+</ul>
14
+

+ 33 - 0
app/front/templates/front/_promotions.html

@@ -0,0 +1,33 @@
1
+<div id="promotions" class="carousel slide" data-ride="carousel">
2
+    <ol class="carousel-indicators">
3
+        {% for o in objs %}
4
+            {% if o.featureImage %}
5
+            <li data-target="#promotions" data-slide-to="{{ forloop.counter0 }}"></li>
6
+            {% endif %}
7
+        {% endfor %}
8
+    </ol>
9
+  <div class="carousel-inner">
10
+      {% for o in objs %}
11
+        {% if o.featureImage %}
12
+        <div class="carousel-item {{ forloop.first|yesno:"active," }}">
13
+                <div class='img-container-16-9'>
14
+                <img src="{{ o.featureImage.url }}" class="d-block w-100 media" alt="...">
15
+                </div>
16
+                <div class="carousel-caption d-none d-md-block">
17
+                    <a href='https://www.google.com' class='text-decoration-none text-white'>
18
+                    <h5>{{ o.title }}</h5>
19
+                    <p>{{ o.description }}</p></a>
20
+                </div>
21
+            </div>
22
+        {% endif %}
23
+      {% endfor %}
24
+  </div>
25
+   <button class="carousel-control-prev border-0" type="button" data-target="#promotions" data-slide="prev">
26
+    <span class="carousel-control-prev-icon" aria-hidden="true"></span>
27
+    <span class="sr-only">Previous</span>
28
+  </button>
29
+  <button class="carousel-control-next border-0" type="button" data-target="#promotions" data-slide="next">
30
+    <span class="carousel-control-next-icon" aria-hidden="true"></span>
31
+    <span class="sr-only">Next</span>
32
+  </button>
33
+</div>

+ 17 - 0
app/front/templates/front/_recs.html

@@ -0,0 +1,17 @@
1
+<h2 class='text-center mt-4 mb-2'>Recommended</h2> 
2
+<div class="card-columns">
3
+    {% for o in objs %}
4
+  <div class="card">
5
+      <img src="{{ o.featureImage.url }}" class="card-img-top" alt="...">
6
+    <div class="card-body">
7
+        <h5 class="card-title">
8
+            <a href="{% url "front:viewPost"   pid=o.id %}?cstr={{ storeFront.storeId }}">{{ o.title }}</a>
9
+        </h5>
10
+      <p class="card-text">
11
+        {{ o.description }}
12
+        Cras justo odio, dapibus ac facilisis in, egestas eget quam. Sed posuere consectetur est at lobortis.
13
+      </p>
14
+    </div>
15
+  </div>
16
+    {% endfor %}
17
+</div>

+ 25 - 0
app/front/templates/front/_relate_menus.html

@@ -0,0 +1,25 @@
1
+<h2 class='text-center mt-4 mb-2'>Relate Menus</h2> 
2
+<div class="row">
3
+    {% for o in objs %}
4
+    {% if forloop.counter|divisibleby:4 %}
5
+      <div class="card text-white bg-primary col-md-4 p-0">
6
+    {% elif forloop.counter|divisibleby:3 %}
7
+      <div class="card text-white bg-secondary col-md-4 p-0">
8
+    {% elif forloop.counter|divisibleby:2  %}
9
+      <div class="card text-white bg-success col-md-4 p-0">
10
+    {% elif forloop.counter|divisibleby:1 %}
11
+      <div class="card text-white bg-danger col-md-4 p-0">
12
+    {% endif %}
13
+    {% if o.featureImage %}
14
+        <div class='img-container-16-9'>
15
+            <img class="card-img-top media" src="{{ o.featureImage.url }}" alt="Card image cap">
16
+        </div>
17
+        {% endif %}
18
+    <div class="card-body">
19
+        <h5 class="card-title">{{ o.name }}</h5>
20
+        <p class="card-text">{{ o.description }}</p>
21
+        <p class="card-text"><small class="text-white">{{ o.created_at }}</small></p>
22
+    </div>
23
+  </div>
24
+  {% endfor %}
25
+</div>

+ 23 - 0
app/front/templates/front/_reviews.html

@@ -0,0 +1,23 @@
1
+<h2 class='text-center mt-4 mb-2'>Reviews</h2> 
2
+<div class="row">
3
+    {% for o in objs %}
4
+    {% if forloop.counter|divisibleby:4 %}
5
+      <div class="card text-white bg-primary col-md-4 p-0">
6
+    {% elif forloop.counter|divisibleby:3 %}
7
+      <div class="card text-white bg-secondary col-md-4 p-0">
8
+    {% elif forloop.counter|divisibleby:2  %}
9
+      <div class="card text-white bg-success col-md-4 p-0">
10
+    {% elif forloop.counter|divisibleby:1 %}
11
+      <div class="card text-white bg-danger col-md-4 p-0">
12
+    {% endif %}
13
+        <div class='img-container-16-9'>
14
+            <img class="card-img-top media" src="{{ o.featureImage.url }}" alt="Card image cap">
15
+        </div>
16
+    <div class="card-body">
17
+        <h5 class="card-title">{{ o.title }}</h5>
18
+        <p class="card-text">{{ o.description }}</p>
19
+        <p class="card-text"><small class="text-white">{{ o.created_at }}</small></p>
20
+    </div>
21
+  </div>
22
+  {% endfor %}
23
+</div>

+ 82 - 0
app/front/templates/front/base.html

@@ -0,0 +1,82 @@
1
+{% load static %}
2
+<!DOCTYPE html>
3
+<html lang="en">
4
+<head>
5
+    <title>
6
+        FindBed.xyz ทำเพื่อช่วยเหลือในการหาเตียงสำหรับผู้ป่วย COVID19
7
+    </title>
8
+    <meta name="description" content="FindBed.xyz ทำเพื่อช่วยเหลือในการหาเตียงสำหรับผู้ป่วย COVID19">
9
+     <!-- Include meta tag to ensure proper rendering and touch zooming -->
10
+  <meta name="viewport" content="width=device-width, initial-scale=1">
11
+  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
12
+  <!--
13
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> -->
14
+
15
+  <!-- Include the jQuery library -->
16
+  <!--
17
+  <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script> -->
18
+  <script src="{% static "bower_components/jQuery/dist/jquery.min.js" %}"></script>
19
+  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
20
+<!-- 
21
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> -->
22
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css">
23
+
24
+  <link href="https://fonts.googleapis.com/css?family=Playfair+Display:700,900" rel="stylesheet">
25
+{% block header %}
26
+{% endblock %}
27
+    <link href="{% static "front/css/blog.css" %}" rel="stylesheet">
28
+    <link href="{% static "bower_components/components-font-awesome/css/all.css" %}" rel="stylesheet">
29
+<script type='text/javascript' src="{% static "js/main.js" %}"></script>
30
+{% if store %}
31
+{% autoescape off %}
32
+    <script type='text/javascript'>
33
+        {{ store.code.jsCode }}        
34
+    </script>
35
+    <style>
36
+        {{ store.code.cssCode }}        
37
+    </style>
38
+    {{ store.code.pluginCode }}
39
+{% endautoescape %}
40
+{% endif %}
41
+{% block header_script %}
42
+{% endblock %}
43
+</head>
44
+
45
+<body>
46
+	<div class="container">
47
+		{% include "front/_menu.html" %}
48
+		{% block top_slide %}	
49
+		{% endblock %}  
50
+	</div>
51
+	<main role="main" class="container">
52
+        {% include "_messages.html" %}
53
+		{% block content %}
54
+		{% endblock %}
55
+	</main><!-- /.container -->
56
+	<footer class="blog-footer container">
57
+      <hr>
58
+		<p>Blog template built for <a href="https://getbootstrap.com/">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p>
59
+		<p>
60
+		<a href="#">Back to top</a>
61
+		</p>
62
+	</footer>
63
+
64
+
65
+<script src="{% static "bower_components/holderjs/holder.min.js" %}"></script>
66
+<!-- 
67
+<script src="{% static "bower_components/popper.js/src/popper.js" %}"></script> -->
68
+
69
+    <!--
70
+     The `defer` attribute causes the callback to execute after the full HTML
71
+     document has been parsed. For non-blocking uses, avoiding race conditions,
72
+     and consistent behavior across browsers, consider loading using Promises
73
+     with https://www.npmjs.com/package/@googlemaps/js-api-loader.
74
+    -->
75
+    <script
76
+      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAR9ZPbOmfQchxZZn4l71Cxhdet5Ye1DNw&callback=initMap&v=weekly"
77
+      defer
78
+    ></script>
79
+    {% block foot_script %}
80
+    {% endblock %}
81
+</body>
82
+</html>

+ 6 - 0
app/front/templates/front/index.html

@@ -0,0 +1,6 @@
1
+{% extends "front/base.html" %}
2
+
3
+{% load static %}
4
+{% block content %}
5
+Hello World
6
+{% endblock %}

+ 22 - 0
app/front/templates/front/myStore.html

@@ -0,0 +1,22 @@
1
+{% extends "front/base.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+
6
+{% block content %}
7
+<h1>My Store</h1>
8
+{{ pos }}
9
+
10
+{% for p in primaryMenu %}
11
+    {{ p.name }}
12
+{% endfor %}
13
+
14
+{% include "front/_menu_ui.html" with menu=primaryMenu %}
15
+{{ storeInfo | safe }}
16
+
17
+<form  method="post">
18
+    {% csrf_token %}
19
+    {{ form  | crispy }}
20
+    <input type="submit" class='btn btn-primary' value="Save">
21
+</form>
22
+{% endblock %}

+ 30 - 0
app/front/templates/front/search.html

@@ -0,0 +1,30 @@
1
+{% extends "front/storeFront.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+{% load pos_filters %}
6
+
7
+{% block content %}
8
+{% if results %}
9
+<h1 class='text-center mt-4 mb-4'>Search Results</h1>
10
+<div class='card-columns'>
11
+{% for r in results %}
12
+<div class="card">
13
+    {% if  r|className == "Post" %}
14
+    <img src="{{ r.featureImage.url }}" class="card-img-top" alt="...">
15
+    <div class="card-body">
16
+        <h5 class="card-title">
17
+            <a href="{% url "front:viewPost"   pid=r.id  %}?cstr={{ r.store.id }}">{{ r.title }}</a>
18
+        </h5>
19
+        <p class="card-text">
20
+        {{ r.description }}</p>
21
+        <p class="card-text"><small class="text-muted">{{ r.created_at }}</small></p>
22
+    </div>
23
+    {% endif %}
24
+</div>
25
+{% endfor %}
26
+</div>
27
+{% else %}
28
+<h1 class='text-center mt-4 mb-4'>Your Search not Matched any Records</h1>
29
+{% endif %}
30
+{% endblock %}

+ 77 - 0
app/front/templates/front/storeContact.html

@@ -0,0 +1,77 @@
1
+{% extends "front/storeFront.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+
6
+{% block content %}
7
+<h1>{{ storeFront.fullName }}</h1>
8
+<div class='row'>
9
+    <div class='col-md-9'>
10
+        <p>
11
+        {{ storeFront.description }}
12
+        </p>
13
+        <div id='map'>
14
+        </div>
15
+    </div>
16
+    <div class='col-md-3'>
17
+        <dl>
18
+            <dt>Address</dt>
19
+            <dd>
20
+        {{ storeFront.addressText }}
21
+            </dd>
22
+            <dt>Tel</dt>
23
+            <dd>
24
+                <a href="callto:{{ storeFront.tel_number }}">
25
+                    {{ storeFront.tel_number}}
26
+                </a>
27
+            </dd>
28
+            <dt>Fax</dt>
29
+            <dd>
30
+                <a href="callto:{{ storeFront.fax_number }}">
31
+                    {{ storeFront.fax_number }}</a>
32
+            </dd>
33
+            <dt>LineID</dt>
34
+            <dd>
35
+                <a href="https://line.me/R/{{ storeFront.lineId }}">
36
+                    {{ storeFront.lineId }}</a>
37
+            </dd>
38
+            <dt>Email</dt>
39
+            <dd>
40
+                <a href="mailto:{{ storeFront.email }}">
41
+                    {{ storeFront.email }}</a>
42
+            </dd>
43
+        </dl>
44
+    </div>
45
+</div>
46
+{% endblock %}
47
+
48
+{% block header_script %}
49
+<style type='text/css'>
50
+#map {
51
+  height: 600px;
52
+}
53
+
54
+</style>
55
+{% endblock %}
56
+
57
+{% block foot_script %}
58
+    <script type='text/javascript'>
59
+        let map;
60
+
61
+        function initMap() {
62
+                let latLng = {lat: {{ geo.lat }}, lng: {{ geo.lon }} }; 
63
+                map = new google.maps.Map(document.getElementById("map"), {
64
+                    center: latLng,
65
+                    zoom: 8,
66
+                });
67
+                new google.maps.Marker({
68
+                        position: latLng,
69
+                        map,
70
+                        title: "{{ storeFront.fullName }}",
71
+                });
72
+        }
73
+                //initMap();
74
+        window.initMap = initMap;
75
+
76
+    </script>
77
+{% endblock %}

+ 34 - 0
app/front/templates/front/storeFront.html

@@ -0,0 +1,34 @@
1
+{% extends "front/base.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+
6
+{% block content %}
7
+{% include "front/_localSearch.html" %}
8
+{% if storeFront %}
9
+
10
+<div class="card mb-3">
11
+    <div class="row no-gutters">
12
+        <div class="col-md-4">
13
+            {% if storeFront.logo %}
14
+            <img src="{{ storeFront.logo }}" class="rounded-circle" alt="Cinque Terre">
15
+            {% endif %}
16
+        </div>
17
+        <div class="col-md-8">
18
+            <div class="card-body">
19
+                <h5 class="card-title">{{ storeFront.fullName }}</h5>
20
+                <p class="card-text">
21
+                    {% firstof storeFront.description " " %}
22
+                </p>
23
+                <a class='btn btn-primary btn-sm' href="{% url  "front:viewStoreMap" %}?cstr={{ storeFront.storeId }}" target="_blank">View Map</a>
24
+                <a class='btn btn-danger btn-sm' href="">Follow</a>
25
+                <a class='btn btn-secondary btn-sm' href="">Share</a>
26
+            </div>
27
+        </div>
28
+    </div>
29
+</div>
30
+{% endif %}
31
+{% include "front/_promotions.html" with objs=promotions %}
32
+{% include "front/_recs.html" with objs=recs %}
33
+{% include "front/_reviews.html" with objs=reviews %}
34
+{% endblock %}

+ 95 - 0
app/front/templates/front/storeMap.html

@@ -0,0 +1,95 @@
1
+{% extends "front/storeFront.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+
6
+{% block content %}
7
+<h1>{{ storeFront.fullName }}</h1>
8
+<div class='row'>
9
+    <div class='col-md-9'>
10
+        <p>
11
+        {{ storeFront.description }}
12
+        </p>
13
+        <form method='post' enctype="multipart/form-data" >
14
+            {% csrf_token %}
15
+            <div class="card w-100">
16
+                 <div class="card-header">Contact Us</div>
17
+                <div class="card-body">
18
+            <div class="row">
19
+            <div class="col-md-6">{{ form.subject | as_crispy_field }}</div>
20
+            <div class="col-md-6">{{ form.email | as_crispy_field }}</div>
21
+            <div class="col-md-6">{{ form.tel | as_crispy_field }}</div>
22
+            <div class="col-md-6">{{ form.lineId | as_crispy_field }}</div>
23
+            <div class="col-md-12">{{ form.body | as_crispy_field }}</div>
24
+            <div class="col-md-12">{{ form.messageFile | as_crispy_field }}</div>
25
+            </div>
26
+            <input type='submit' value='Save' class='btn btn-primary btn-block'>
27
+                </div>
28
+            </div>
29
+        </form>
30
+        <hr>
31
+        <div id='map'>
32
+        </div>
33
+    </div>
34
+    <div class='col-md-3'>
35
+        <dl>
36
+            <dt>Address</dt>
37
+            <dd>
38
+        {{ storeFront.addressText }}
39
+            </dd>
40
+            <dt>Tel</dt>
41
+            <dd>
42
+                <a href="callto:{{ storeFront.tel_number }}">
43
+                    {{ storeFront.tel_number}}
44
+                </a>
45
+            </dd>
46
+            <dt>Fax</dt>
47
+            <dd>
48
+                <a href="callto:{{ storeFront.fax_number }}">
49
+                    {{ storeFront.fax_number }}</a>
50
+            </dd>
51
+            <dt>LineID</dt>
52
+            <dd>
53
+                <a href="https://line.me/R/{{ storeFront.lineId }}">
54
+                    {{ storeFront.lineId }}</a>
55
+            </dd>
56
+            <dt>Email</dt>
57
+            <dd>
58
+                <a href="mailto:{{ storeFront.email }}">
59
+                    {{ storeFront.email }}</a>
60
+            </dd>
61
+        </dl>
62
+    </div>
63
+</div>
64
+{% endblock %}
65
+
66
+{% block header_script %}
67
+<style type='text/css'>
68
+#map {
69
+  height: 600px;
70
+}
71
+
72
+</style>
73
+{% endblock %}
74
+
75
+{% block foot_script %}
76
+    <script type='text/javascript'>
77
+        let map;
78
+
79
+        function initMap() {
80
+                let latLng = {lat: {{ geo.lat }}, lng: {{ geo.lon }} }; 
81
+                map = new google.maps.Map(document.getElementById("map"), {
82
+                    center: latLng,
83
+                    zoom: 8,
84
+                });
85
+                new google.maps.Marker({
86
+                        position: latLng,
87
+                        map,
88
+                        title: "{{ storeFront.fullName }}",
89
+                });
90
+        }
91
+                //initMap();
92
+        window.initMap = initMap;
93
+
94
+    </script>
95
+{% endblock %}

+ 18 - 0
app/front/templates/front/viewPost.html

@@ -0,0 +1,18 @@
1
+{% extends "front/storeFront.html" %}
2
+{% load mptt_tags %}
3
+{% load static %}
4
+{% load crispy_forms_tags %}
5
+
6
+{% block content %}
7
+<h1>{{ post.title }}</h1>
8
+<div class='row'>
9
+    <div class='col-md-9'>
10
+        <div class='content-wrap'>
11
+            {{ post.content | safe  }}
12
+        </div>
13
+    {% include "front/_relate_menus.html" with objs=post.relateMenus.all %}
14
+    </div>
15
+    <div class='col-md-3'>
16
+    </div>
17
+</div>
18
+{% endblock %}

+ 3 - 0
app/front/tests.py

@@ -0,0 +1,3 @@
1
+from django.test import TestCase
2
+
3
+# Create your tests here.

+ 16 - 0
app/front/urls.py

@@ -0,0 +1,16 @@
1
+from django.urls import path
2
+
3
+from . import views
4
+
5
+urlpatterns = [
6
+    path('', views.index, name='index'),
7
+    path('search', views.search, name='search'),
8
+    path('myStore', views.myStore, name='myStore'),
9
+    path('store', views.storeFrontView, name='storeFront'),
10
+    path('store/<storeId>/menus', views.storeMenus, name='viewStoreMenus'),
11
+    path('menus/<menuId>', views.viewMenu, name='viewMenu'),
12
+    path('store/posts/<pid>', views.viewPost, name='viewPost'),
13
+    path('store/map', views.viewStoreMap, name='viewStoreMap'),
14
+    path('store/contact', views.storeContact, name='storeContact'),
15
+]
16
+app_name = 'front'

+ 87 - 0
app/front/views.py

@@ -0,0 +1,87 @@
1
+from django.shortcuts import render, redirect, reverse
2
+from django.contrib.auth.decorators import login_required
3
+from pos.pos import PosSys
4
+from pos.storefront import StoreFront
5
+from django.http import JsonResponse
6
+from django.contrib import messages
7
+# Create your views here.
8
+def index(request):
9
+    return render(request,'front/index.html')
10
+
11
+@login_required
12
+def myStore(request):
13
+    pos = PosSys.restoreStore(request.user)
14
+    storeInfo = pos.uiSys.renderStoreInfo()
15
+    primaryMenu = pos.uiSys.menu('primary')
16
+    formInstance = pos.uiSys.form('tableForm')
17
+
18
+    print("Instance")
19
+    print(formInstance)
20
+
21
+    if request.method == "POST":
22
+        formInstance = pos.uiSys.form('tableForm', request=request)
23
+        if formInstance.is_valid():
24
+            formInstance.save()
25
+            print("valid")
26
+        else:
27
+            print(formInstance.errors)
28
+            print("invalide")
29
+        return redirect('front:myStore')
30
+
31
+    return render(request, 'front/mystore.html', {'pos': pos, 'storeInfo': storeInfo, 'primaryMenu': primaryMenu, 'form': formInstance})
32
+
33
+def storeFrontView(request):
34
+    if request.storeFront:
35
+        menus = request.storeFront.getMenus()[:10]
36
+        promotions = request.storeFront.getPosts(cat='Promotions')
37
+        recs = request.storeFront.getPosts(cat="Recommendations")
38
+        reviews = request.storeFront.getPosts(cat="Reviews")
39
+        return render(request, 'front/storeFront.html', {'promotions': promotions, 'recs': recs, 'reviews': reviews, 'menus': menus})
40
+    return JsonResponse({'msg': "Please provide store id in querystring"})
41
+
42
+
43
+def storeMenus(request, storeId):
44
+    return render(request, 'front/storeMenus.html')
45
+
46
+def viewMenu(request, menuId):
47
+    return render(request, 'front/viewMenu.html')
48
+
49
+def viewPost(request, pid):
50
+    post = request.storeFront.getPostById(pid)
51
+    return render(request, 'front/viewPost.html', {'post': post})
52
+
53
+def viewStoreMap(request):
54
+    location = request.storeFront.location
55
+    form = request.storeFront.messageForm()
56
+    if request.method == 'POST':
57
+        form = request.storeFront.messageForm(request=request)
58
+        if form.is_valid():
59
+            o = form.save(commit=False)
60
+            o.store = request.storeFront.store
61
+            o.save()
62
+            messages.success(request, 'Thank you for your contact')
63
+            return redirect(reverse('front:viewStoreMap')+f"?cstr={request.storeFront.storeId}")
64
+    return render(request, 'front/storeMap.html', {'geo': location[1], 'address': location[0], 'form': form})
65
+
66
+
67
+def storeContact(request):
68
+    form = request.storeFront.messageForm()
69
+    if request.method == 'POST':
70
+        form = request.storeFront.messageForm(request=request)
71
+        if form.is_valid():
72
+            o = form.save()
73
+            messages.success(request, 'Thank you for your contact')
74
+            return redirect(reverse('front:storeContact')+"?cstr="+request.storeFront.storeId)
75
+    return render(request, 'front/storeContact.html', {'form': form})
76
+
77
+def search(request):
78
+    results  = None
79
+    q = request.GET.get('q', '')
80
+    print(q)
81
+    if request.storeFront:
82
+        results = request.storeFront.search(q=q)
83
+    else:
84
+        results = StoreFront.globalSearch(q)
85
+        print(results)
86
+    return render(request, 'front/search.html', {'results': results})
87
+

+ 28 - 0
app/key.pem

@@ -0,0 +1,28 @@
1
+-----BEGIN PRIVATE KEY-----
2
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDM7eQObxKic7Y/
3
++lI5CYU9iiPb5/PycR3myz68v95FzkFomyrXrnWCUh07JRfXcHgTS+JMXRprpI/2
4
+NktTqU+W4nBblRgK5VJbrvAvQS8LzZMGkHPaEwa4LoNykbScmDNjTiS7PSYlqpa1
5
+YPgAyrcE7CAE3LY+sHjlxQYEF7du+wKKn3KRVby8cRYqAel2dm9Ridttt5r2MNH+
6
+cHRwN4p3krjlX8u/YQIEAZrbvYL1r26pe7MhxUWx05v2yzpg3KJKzUAl5dNXXozm
7
+7pmVU33khT0AepbF5MJVjIZlZm2DVcPswH8zbb+YNSNmDV90re/af5EXHKj8Uag0
8
+TrOIALPrAgMBAAECggEBALGtmMwC9c8wMFYsPVoCrSl8OjcSV2pfNSPEGLMiUB+K
9
+AyAlWPID6xKBC6MaOB+s/g8M/jpjhuLJnaBF1u3EoKMb1XsyO9RGnC+t78Wo6Jd9
10
+N/q7CBeN44eRnJqbRlN3iyaQvDwzen2x+FVuq9hT6nc0G1bb3o9gBpKBTwQBZCOt
11
+o4djb1dkSx3qB917VC4+0yK1pknliANxxdVcq8ZHfcY3G7xkgV8crn5UB95HmFAp
12
+9sJ1XxpXHqoD+lgLakQKhgHOTqQdb0mbMOPkHA5Zw2YRV89FaYc2m+if3rWyaK4z
13
+yk9hSd8/LK71rmYO0YlVDGwWkhUkDAD3q/T20kpeFxECgYEA/Uf5PqKc3Z9k6bTp
14
+3JnfMNrXY4Nk1pE8apZF1Saho8mKsCX0Vm3x4DC8xZgwE5gvMusopHWp/EoCvMet
15
+5/EJpNXzjLZB35IdAiGCYQPLEQTQjmCtsQIRoknhZc9nKPw/iWlev68Yrrf16jkj
16
+9FrvyyFEWQ4wUgQftPC/7u5Ad58CgYEAzyELXIxtXpXdjch0X9L7IRULuQ4Rs7q3
17
+7+TvFYd5P0X2zBBJ7AHjamaru7C+ytnT7bpSudRv36k9KySsHtqGKl9uSJrGGJeW
18
+kqQ9wOorwu9PDVvdL2DxG31bK5b+BcQhqSPYJEVe3FpETJgtbFNIIf9LEVg73v91
19
+iNiNqbwSEDUCgYEAq7poCQrSVwWisz7BrZv6kzJeBY/qB/1TPGWFFZ9qyxV0Xjht
20
+sUg8TihdZY/pUO/HWLvOw6svxOodbwfoJrHsOwIBbu+IPGDiIDa+Iq8iuPhNu6tb
21
+OP/RGvsCwzfblxNotO9nmYnLr3L1Xoi9kwkxOsXkhIk1Q/ad1N3DFOofdbsCgYAq
22
+X2kymqu5INF9MtfTzpZ/Uw3d4qnuabE9S0k5z0gXkJmHb4Gf3VcHqk9RizvMxbkc
23
+NfS8fWARkk6oJ81qVmwB+RnXkooZ99De2OilMYKYU1qJshRSn/NTG1buWOpIhbIZ
24
+JvMNoH9idrjoLm2EbpkgE1jpCHLfEMWbpCl+4rGTTQKBgQCvOqqWpwS0fJFwbx1h
25
+F+jcLf9eQHD5B/kh91f4dvB3Uywi2vP5pkAPkRS2dd6z5ZKNuHCCUYizKDR6d20g
26
+EnGUuN96uyby4vT5Xar1/6IWcJl2VpjHAUjGAKw2PHRA4ti+RO7oo4TP9J/tF/Ec
27
+xoO0p1jYKttMAiKBlw10sNBZmg==
28
+-----END PRIVATE KEY-----

+ 22 - 0
app/manage.py

@@ -0,0 +1,22 @@
1
+#!/usr/bin/env python
2
+"""Django's command-line utility for administrative tasks."""
3
+import os
4
+import sys
5
+
6
+
7
+def main():
8
+    """Run administrative tasks."""
9
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'simpliPos.settings')
10
+    try:
11
+        from django.core.management import execute_from_command_line
12
+    except ImportError as exc:
13
+        raise ImportError(
14
+            "Couldn't import Django. Are you sure it's installed and "
15
+            "available on your PYTHONPATH environment variable? Did you "
16
+            "forget to activate a virtual environment?"
17
+        ) from exc
18
+    execute_from_command_line(sys.argv)
19
+
20
+
21
+if __name__ == '__main__':
22
+    main()

BIN
app/mycert.cer


+ 0 - 0
app/pos/__init__.py


+ 70 - 0
app/pos/admin.py

@@ -0,0 +1,70 @@
1
+from django.contrib import admin
2
+from .models import Store, MenuItem, Setting, StoreFile, Table, BookingTable, Order,  MenuFile, OrderItem, UIMenu, PostCategory, Post
3
+from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin
4
+from mptt.admin import MPTTModelAdmin
5
+from django_admin_hstore_widget.forms import HStoreFormField
6
+
7
+from django.contrib.postgres.fields import HStoreField, ArrayField
8
+
9
+from django import forms
10
+
11
+
12
+
13
+
14
+# Register your models here.
15
+
16
+class StoreFileAdmin(admin.TabularInline):
17
+    model = StoreFile
18
+
19
+class MenuItemAdmin(admin.StackedInline):
20
+    model = MenuItem
21
+
22
+class OrderItemAdmin(admin.TabularInline):
23
+    model = OrderItem
24
+
25
+class StoreAdmin(admin.ModelAdmin):
26
+   inlines = [StoreFileAdmin, MenuItemAdmin]
27
+   formfield_overrides = {
28
+        HStoreField: {'widget': HStoreFormField},
29
+    }
30
+
31
+class SettingAdmin(admin.ModelAdmin):
32
+    pass
33
+
34
+class OrderAdmin(admin.ModelAdmin):
35
+   inlines = [OrderItemAdmin,]
36
+
37
+
38
+class SettingAdminForm(forms.ModelForm):
39
+    data = HStoreFormField()
40
+
41
+    class Meta:
42
+       model = Setting
43
+       exclude = ()
44
+
45
+@admin.register(Setting)
46
+class SettingAdmin(admin.ModelAdmin):
47
+    form = SettingAdminForm
48
+
49
+@admin.register(Post)
50
+class PostAdmin(admin.ModelAdmin):
51
+    list_display = ('title', 'tag_list', 'cats', 'created_at', 'store', 'featureImage')
52
+    save_as = True
53
+
54
+    def tag_list(self, obj):
55
+        return u", ".join(o.name for o in obj.tags.all())
56
+
57
+
58
+admin.site.register(Store, StoreAdmin)
59
+admin.site.register(MenuItem)
60
+#admin.site.register(Setting, SettingAdmin)
61
+admin.site.register(StoreFile)
62
+admin.site.register(Table)
63
+admin.site.register(BookingTable)
64
+admin.site.register(Order, OrderAdmin)
65
+admin.site.register(MenuFile)
66
+admin.site.register(UIMenu, MPTTModelAdmin)
67
+#admin.site.register(Post)
68
+admin.site.register(PostCategory, MPTTModelAdmin)
69
+
70
+

+ 6 - 0
app/pos/apps.py

@@ -0,0 +1,6 @@
1
+from django.apps import AppConfig
2
+
3
+
4
+class PosConfig(AppConfig):
5
+    default_auto_field = 'django.db.models.BigAutoField'
6
+    name = 'pos'

+ 53 - 0
app/pos/context_processors.py

@@ -0,0 +1,53 @@
1
+from django.conf import settings
2
+from .pos import PosSys
3
+from .storefront import StoreFront
4
+import json
5
+from .models import Store
6
+
7
+def pos(request):
8
+    store = Store.objects.get(pk=settings.STORE_ID)
9
+    cstr = request.GET.get('cstr', None)
10
+    if cstr:
11
+        storeFront = StoreFront(int(cstr))
12
+    else:
13
+        storeFront = None
14
+
15
+    if hasattr(request, 'user') and request.user.is_authenticated:
16
+        user = request.user
17
+        pos = PosSys.restoreStore(user)
18
+        storeInfo = pos.uiSys.renderStoreInfo()
19
+
20
+        #ms = jso.loads(pos.settingSys.get('menus'))
21
+        ms = []
22
+        try:
23
+            ms = json.loads(pos.settingSys.get('menus'))
24
+        except TypeError:
25
+            ms = []
26
+
27
+        print(ms)
28
+        print(type(ms))
29
+        temp = []
30
+        for i in ms:
31
+            temp.append({'title': i['title'], 'menu': pos.uiSys.menu(i['name'])})
32
+            #ms.append(pos.uiSys.menu(m))
33
+
34
+        ctx  = {
35
+            'pos': pos,
36
+            'info': storeInfo,
37
+            'menus': temp,
38
+            'primaryMenu': pos.uiSys.menu('primary'),
39
+            'store': store,
40
+            'storeFront': storeFront,
41
+        }
42
+        return ctx
43
+    else:
44
+        ctx = {
45
+            'pos': None,
46
+            'info': None,
47
+            'menus': [],
48
+            'store': store,
49
+            'storeFront': storeFront,
50
+        }
51
+        return ctx
52
+
53
+

+ 159 - 0
app/pos/forms.py

@@ -0,0 +1,159 @@
1
+from pos.models import MenuItem, Store, Setting, Table, BookingTable, Order, OrderItem, UIMenu, Post, PostCategory, Customer, Code, Profile, Message
2
+
3
+from django.forms import ModelForm
4
+import django_filters
5
+
6
+from django.forms import BaseInlineFormSet, DateField, TimeField, TextInput, ModelMultipleChoiceField, CheckboxSelectMultiple
7
+
8
+from mptt.forms import TreeNodeMultipleChoiceField
9
+from django_editorjs_fields import EditorJsWidget
10
+from django.contrib.auth.models import User
11
+from django_google_maps.widgets import GoogleMapsAddressWidget
12
+
13
+class TableForm(ModelForm):
14
+    class Meta:
15
+        model = Table
16
+        fields = ('code', 'nSeats', 'occupy',)
17
+
18
+class MessageForm(ModelForm):
19
+    class Meta:
20
+        model = Message
21
+        fields = ('subject', 'email', 'tel', 'body', 'messageFile', 'lineId', 'reply', 'parent', )
22
+
23
+class UIMenuForm(ModelForm):
24
+    class Meta:
25
+        model = UIMenu
26
+        fields = ('name', 'parent', 'group', 'url', 'icon', 'nOrder', )
27
+
28
+class OrderForm(ModelForm):
29
+    class Meta:
30
+        model = Order
31
+        fields = '__all__'
32
+
33
+class PostForm(ModelForm):
34
+    #category = TreeNodeMultipleChoiceField(queryset=PostCategory.objects.all())
35
+    '''
36
+    relateMenus = ModelMultipleChoiceField(
37
+        queryset=MenuItem.objects.all(),
38
+        widget=CheckboxSelectMultiple,
39
+        required=False)
40
+    '''
41
+
42
+    class Meta:
43
+        model = Post
44
+        fields = ('featureImage', 'title', 'content', 'description', 'category', 'tags', 'relateMenus' )
45
+
46
+class CustomerForm(ModelForm):
47
+    #category = TreeNodeMultipleChoiceField(queryset=PostCategory.objects.all())
48
+
49
+    class Meta:
50
+        model = Customer
51
+        fields = ('fullName', 'email', 'lineId', 'gender', )
52
+
53
+class BookingForm(ModelForm):
54
+    onDate = DateField(
55
+        widget=TextInput(
56
+            attrs={'type': 'date'}
57
+        )
58
+    )
59
+    onTime = TimeField(
60
+        widget=TextInput(
61
+            attrs={'type': 'time'}
62
+        )
63
+    )
64
+    class Meta:
65
+        model = BookingTable
66
+        fields = ('table', 'onDate',  'onTime', 'note',)
67
+
68
+class MenuItemForm(ModelForm):
69
+    class Meta:
70
+        model = MenuItem
71
+        fields = ['featureImage', 'name', ]
72
+
73
+class StoreForm(ModelForm):
74
+    class Meta:
75
+        model = Store
76
+        fields = ['logo', 'name','description', 'addressText', 'province','address',  'phone_number', 'fax_number', 'lineId',  'email', 'geolocation',  'storeType']
77
+
78
+        widgets = {
79
+            "address": GoogleMapsAddressWidget,
80
+        }
81
+
82
+class OrderItemFormSet(BaseInlineFormSet):
83
+    def __init__(self, other_model_queryset, *args, **kwargs):
84
+        super(BaseInlineFormSet, self).__init__(*args)
85
+
86
+        for form in self.forms:
87
+            form.fields['item'].queryset = other_model_queryset
88
+
89
+
90
+formMap = {
91
+    'tableForm': TableForm
92
+}
93
+
94
+class OrderFilter(django_filters.FilterSet):
95
+    note = django_filters.CharFilter(lookup_expr='iexact')
96
+
97
+    class Meta:
98
+        model = Order
99
+        fields = ['table', 'note']
100
+
101
+class MenuItemFilter(django_filters.FilterSet):
102
+    class Meta:
103
+        model = MenuItem
104
+        fields = ['name', ]
105
+
106
+class StoreFilter(django_filters.FilterSet):
107
+    class Meta:
108
+        model = Store
109
+        fields = ('name', 'address', 'province','storeType')
110
+
111
+class BookingFilter(django_filters.FilterSet):
112
+    class Meta:
113
+        model = BookingTable
114
+        fields = ('table', 'onDate', 'note', )
115
+
116
+class CustomerFilter(django_filters.FilterSet):
117
+    class Meta:
118
+        model = Customer
119
+        fields = ('fullName', 'email', 'lineId', 'gender', 'created_at', )
120
+
121
+class TableFilter(django_filters.FilterSet):
122
+    class Meta:
123
+        model = Table
124
+        fields = ('code', 'nSeats', 'occupy', )
125
+
126
+class UIMenuFilter(django_filters.FilterSet):
127
+    class Meta:
128
+        model = UIMenu
129
+        fields = ('name', 'parent', 'group', 'url', 'icon','nOrder')
130
+
131
+class MessageFilter(django_filters.FilterSet):
132
+    class Meta:
133
+        model = Message
134
+        fields = ('subject', 'email', 'tel', 'body', 'reply', 'parent', 'created_at',  )
135
+
136
+class PostFilter(django_filters.FilterSet):
137
+    class Meta:
138
+        model = Post
139
+        fields = ('title', 'content', )
140
+
141
+class UserFilter(django_filters.FilterSet):
142
+    profile__role = django_filters.ChoiceFilter(label="Role", choices=Profile.ROLE_CHOICES)
143
+
144
+    class Meta:
145
+        model = User
146
+        fields = ('username', 'first_name', 'last_name', 'email', )
147
+
148
+
149
+
150
+
151
+class CodeForm(ModelForm):
152
+    class Meta:
153
+        model = Code
154
+        exclude = ['store', 'owner',]
155
+        widgets = {
156
+            'body_editorjs': EditorJsWidget(config={'minHeight': 100}),
157
+            'body_editorjs_text': EditorJsWidget(plugins=["@editorjs/image", "@editorjs/header"]),
158
+        }
159
+

+ 22 - 0
app/pos/middleware.py

@@ -0,0 +1,22 @@
1
+from django.utils.deprecation import MiddlewareMixin
2
+from .pos import PosSys
3
+from .storefront import StoreFront
4
+
5
+class PosMiddleware(MiddlewareMixin):
6
+    def process_request(self, request):
7
+        if not hasattr(request, "user"):
8
+            raise ImproperlyConfigured(
9
+                "The Django POS middleware requires auth middleware")
10
+        user = request.user
11
+        if user.is_authenticated:
12
+            if not hasattr(request, 'pos') or request.pos is None:
13
+                pos = PosSys.restoreStore(user)
14
+                request.pos = pos
15
+        else:
16
+            request.pos = None
17
+
18
+        cstr  = request.GET.get('cstr', None)
19
+        if cstr:
20
+            request.storeFront = StoreFront(int(cstr))
21
+        else:
22
+            request.storeFront = None

+ 22 - 0
app/pos/migrations/0001_initial.py

@@ -0,0 +1,22 @@
1
+# Generated by Django 3.2.13 on 2022-05-14 08:48
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    initial = True
9
+
10
+    dependencies = [
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='MenuItem',
16
+            fields=[
17
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+                ('name', models.CharField(max_length=100)),
19
+                ('tagline', models.TextField()),
20
+            ],
21
+        ),
22
+    ]

+ 31 - 0
app/pos/migrations/0002_setting_store.py

@@ -0,0 +1,31 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 06:15
2
+
3
+import django.contrib.postgres.fields.hstore
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+
7
+from django.contrib.postgres.operations import HStoreExtension
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        ('pos', '0001_initial'),
13
+    ]
14
+
15
+    operations = [
16
+        HStoreExtension(),
17
+        migrations.CreateModel(
18
+            name='Store',
19
+            fields=[
20
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('name', models.CharField(max_length=100)),
22
+            ],
23
+        ),
24
+        migrations.CreateModel(
25
+            name='Setting',
26
+            fields=[
27
+                ('store', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='pos.store')),
28
+                ('data', django.contrib.postgres.fields.hstore.HStoreField()),
29
+            ],
30
+        ),
31
+    ]

+ 19 - 0
app/pos/migrations/0003_alter_setting_data.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 06:55
2
+
3
+import django.contrib.postgres.fields.hstore
4
+from django.db import migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0002_setting_store'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='setting',
16
+            name='data',
17
+            field=django.contrib.postgres.fields.hstore.HStoreField(blank=True),
18
+        ),
19
+    ]

+ 31 - 0
app/pos/migrations/0004_auto_20220517_1613.py

@@ -0,0 +1,31 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 09:13
2
+
3
+import django.contrib.postgres.fields
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('pos', '0003_alter_setting_data'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AddField(
16
+            model_name='menuitem',
17
+            name='photos',
18
+            field=django.contrib.postgres.fields.ArrayField(base_field=models.FileField(upload_to='uploads/%Y/%m/%d/'), blank=True, null=True, size=8),
19
+        ),
20
+        migrations.AddField(
21
+            model_name='menuitem',
22
+            name='store',
23
+            field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
24
+            preserve_default=False,
25
+        ),
26
+        migrations.AddField(
27
+            model_name='store',
28
+            name='photos',
29
+            field=django.contrib.postgres.fields.ArrayField(base_field=models.FileField(upload_to='uploads/%Y/%m/%d/'), blank=True, null=True, size=8),
30
+        ),
31
+    ]

+ 38 - 0
app/pos/migrations/0005_auto_20220517_2027.py

@@ -0,0 +1,38 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 13:27
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+import taggit.managers
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('taggit', '0005_auto_20220424_2025'),
12
+        ('pos', '0004_auto_20220517_1613'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.RemoveField(
17
+            model_name='menuitem',
18
+            name='photos',
19
+        ),
20
+        migrations.CreateModel(
21
+            name='StoreFile',
22
+            fields=[
23
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
24
+                ('storeFile', models.FileField(upload_to='uploads/%Y/%m/%d/')),
25
+                ('store', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.store')),
26
+                ('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
27
+            ],
28
+        ),
29
+        migrations.CreateModel(
30
+            name='MenuFile',
31
+            fields=[
32
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
33
+                ('menuFile', models.FileField(upload_to='uploads/%Y/%m/%d/')),
34
+                ('store', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.store')),
35
+                ('tags', taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
36
+            ],
37
+        ),
38
+    ]

+ 17 - 0
app/pos/migrations/0006_remove_store_photos.py

@@ -0,0 +1,17 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 13:28
2
+
3
+from django.db import migrations
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0005_auto_20220517_2027'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.RemoveField(
14
+            model_name='store',
15
+            name='photos',
16
+        ),
17
+    ]

+ 25 - 0
app/pos/migrations/0007_auto_20220517_2038.py

@@ -0,0 +1,25 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 13:38
2
+
3
+from django.db import migrations, models
4
+import django.utils.timezone
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0006_remove_store_photos'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='menuitem',
16
+            name='created_at',
17
+            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
18
+            preserve_default=False,
19
+        ),
20
+        migrations.AddField(
21
+            model_name='menuitem',
22
+            name='updated_at',
23
+            field=models.DateTimeField(auto_now=True),
24
+        ),
25
+    ]

+ 58 - 0
app/pos/migrations/0008_auto_20220517_2040.py

@@ -0,0 +1,58 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 13:40
2
+
3
+from django.db import migrations, models
4
+import django.utils.timezone
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0007_auto_20220517_2038'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='menufile',
16
+            name='created_at',
17
+            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
18
+            preserve_default=False,
19
+        ),
20
+        migrations.AddField(
21
+            model_name='menufile',
22
+            name='updated_at',
23
+            field=models.DateTimeField(auto_now=True),
24
+        ),
25
+        migrations.AddField(
26
+            model_name='setting',
27
+            name='created_at',
28
+            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
29
+            preserve_default=False,
30
+        ),
31
+        migrations.AddField(
32
+            model_name='setting',
33
+            name='updated_at',
34
+            field=models.DateTimeField(auto_now=True),
35
+        ),
36
+        migrations.AddField(
37
+            model_name='store',
38
+            name='created_at',
39
+            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
40
+            preserve_default=False,
41
+        ),
42
+        migrations.AddField(
43
+            model_name='store',
44
+            name='updated_at',
45
+            field=models.DateTimeField(auto_now=True),
46
+        ),
47
+        migrations.AddField(
48
+            model_name='storefile',
49
+            name='created_at',
50
+            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
51
+            preserve_default=False,
52
+        ),
53
+        migrations.AddField(
54
+            model_name='storefile',
55
+            name='updated_at',
56
+            field=models.DateTimeField(auto_now=True),
57
+        ),
58
+    ]

+ 55 - 0
app/pos/migrations/0009_bookingtable_order_table.py

@@ -0,0 +1,55 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 15:57
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0008_auto_20220517_2040'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='Table',
16
+            fields=[
17
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+                ('created_at', models.DateTimeField(auto_now_add=True)),
19
+                ('updated_at', models.DateTimeField(auto_now=True)),
20
+                ('nSeats', models.IntegerField(default=1)),
21
+                ('occupy', models.BooleanField(default=False)),
22
+                ('store', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.store')),
23
+            ],
24
+            options={
25
+                'abstract': False,
26
+            },
27
+        ),
28
+        migrations.CreateModel(
29
+            name='Order',
30
+            fields=[
31
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
32
+                ('created_at', models.DateTimeField(auto_now_add=True)),
33
+                ('updated_at', models.DateTimeField(auto_now=True)),
34
+                ('items', models.ManyToManyField(to='pos.MenuItem')),
35
+                ('table', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='pos.table')),
36
+            ],
37
+            options={
38
+                'abstract': False,
39
+            },
40
+        ),
41
+        migrations.CreateModel(
42
+            name='BookingTable',
43
+            fields=[
44
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
45
+                ('created_at', models.DateTimeField(auto_now_add=True)),
46
+                ('updated_at', models.DateTimeField(auto_now=True)),
47
+                ('onDate', models.DateTimeField()),
48
+                ('note', models.TextField(blank=True, null=True)),
49
+                ('table', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.table')),
50
+            ],
51
+            options={
52
+                'abstract': False,
53
+            },
54
+        ),
55
+    ]

+ 18 - 0
app/pos/migrations/0010_table_code.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 16:02
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0009_bookingtable_order_table'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='table',
15
+            name='code',
16
+            field=models.CharField(default='N\\A', max_length=100),
17
+        ),
18
+    ]

+ 32 - 0
app/pos/migrations/0011_auto_20220517_2307.py

@@ -0,0 +1,32 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 16:07
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0010_table_code'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.RemoveField(
15
+            model_name='order',
16
+            name='items',
17
+        ),
18
+        migrations.CreateModel(
19
+            name='OrderItem',
20
+            fields=[
21
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22
+                ('created_at', models.DateTimeField(auto_now_add=True)),
23
+                ('updated_at', models.DateTimeField(auto_now=True)),
24
+                ('qty', models.IntegerField(default=1)),
25
+                ('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.menuitem')),
26
+                ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.order')),
27
+            ],
28
+            options={
29
+                'abstract': False,
30
+            },
31
+        ),
32
+    ]

+ 18 - 0
app/pos/migrations/0012_alter_menuitem_tagline.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-17 16:12
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0011_auto_20220517_2307'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='menuitem',
15
+            name='tagline',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+    ]

+ 103 - 0
app/pos/migrations/0013_auto_20220518_1430.py

@@ -0,0 +1,103 @@
1
+# Generated by Django 3.2.13 on 2022-05-18 07:30
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0012_alter_menuitem_tagline'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='bookingtable',
15
+            name='inProcess',
16
+            field=models.CharField(blank=True, max_length=100, null=True),
17
+        ),
18
+        migrations.AddField(
19
+            model_name='bookingtable',
20
+            name='status',
21
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
22
+        ),
23
+        migrations.AddField(
24
+            model_name='menufile',
25
+            name='inProcess',
26
+            field=models.CharField(blank=True, max_length=100, null=True),
27
+        ),
28
+        migrations.AddField(
29
+            model_name='menufile',
30
+            name='status',
31
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
32
+        ),
33
+        migrations.AddField(
34
+            model_name='menuitem',
35
+            name='inProcess',
36
+            field=models.CharField(blank=True, max_length=100, null=True),
37
+        ),
38
+        migrations.AddField(
39
+            model_name='menuitem',
40
+            name='status',
41
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
42
+        ),
43
+        migrations.AddField(
44
+            model_name='order',
45
+            name='inProcess',
46
+            field=models.CharField(blank=True, max_length=100, null=True),
47
+        ),
48
+        migrations.AddField(
49
+            model_name='order',
50
+            name='status',
51
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
52
+        ),
53
+        migrations.AddField(
54
+            model_name='orderitem',
55
+            name='inProcess',
56
+            field=models.CharField(blank=True, max_length=100, null=True),
57
+        ),
58
+        migrations.AddField(
59
+            model_name='orderitem',
60
+            name='status',
61
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
62
+        ),
63
+        migrations.AddField(
64
+            model_name='setting',
65
+            name='inProcess',
66
+            field=models.CharField(blank=True, max_length=100, null=True),
67
+        ),
68
+        migrations.AddField(
69
+            model_name='setting',
70
+            name='status',
71
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
72
+        ),
73
+        migrations.AddField(
74
+            model_name='store',
75
+            name='inProcess',
76
+            field=models.CharField(blank=True, max_length=100, null=True),
77
+        ),
78
+        migrations.AddField(
79
+            model_name='store',
80
+            name='status',
81
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
82
+        ),
83
+        migrations.AddField(
84
+            model_name='storefile',
85
+            name='inProcess',
86
+            field=models.CharField(blank=True, max_length=100, null=True),
87
+        ),
88
+        migrations.AddField(
89
+            model_name='storefile',
90
+            name='status',
91
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
92
+        ),
93
+        migrations.AddField(
94
+            model_name='table',
95
+            name='inProcess',
96
+            field=models.CharField(blank=True, max_length=100, null=True),
97
+        ),
98
+        migrations.AddField(
99
+            model_name='table',
100
+            name='status',
101
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100),
102
+        ),
103
+    ]

+ 18 - 0
app/pos/migrations/0014_order_note.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-19 14:23
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0013_auto_20220518_1430'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='order',
15
+            name='note',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+    ]

+ 32 - 0
app/pos/migrations/0015_ingredient.py

@@ -0,0 +1,32 @@
1
+# Generated by Django 3.2.13 on 2022-05-19 14:30
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0014_order_note'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.CreateModel(
15
+            name='Ingredient',
16
+            fields=[
17
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18
+                ('created_at', models.DateTimeField(auto_now_add=True)),
19
+                ('updated_at', models.DateTimeField(auto_now=True)),
20
+                ('inProcess', models.CharField(blank=True, max_length=100, null=True)),
21
+                ('status', models.CharField(choices=[('process', 'Process'), ('fn', 'Finished')], default='process', max_length=100)),
22
+                ('name', models.CharField(max_length=200)),
23
+                ('qty', models.DecimalField(decimal_places=2, max_digits=5)),
24
+                ('unit', models.CharField(max_length=10)),
25
+                ('comment', models.TextField(blank=True, null=True)),
26
+                ('menu', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.menuitem')),
27
+            ],
28
+            options={
29
+                'abstract': False,
30
+            },
31
+        ),
32
+    ]

+ 26 - 0
app/pos/migrations/0016_profile.py

@@ -0,0 +1,26 @@
1
+# Generated by Django 3.2.13 on 2022-05-19 14:40
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12
+        ('pos', '0015_ingredient'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.CreateModel(
17
+            name='Profile',
18
+            fields=[
19
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20
+                ('location', models.CharField(blank=True, max_length=30)),
21
+                ('birthdate', models.DateField(blank=True, null=True)),
22
+                ('role', models.PositiveSmallIntegerField(blank=True, choices=[(1, 'Store Owner'), (2, 'Chef'), (3, 'Employee')], null=True)),
23
+                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
24
+            ],
25
+        ),
26
+    ]

+ 66 - 0
app/pos/migrations/0017_auto_20220519_2146.py

@@ -0,0 +1,66 @@
1
+# Generated by Django 3.2.13 on 2022-05-19 14:46
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12
+        ('pos', '0016_profile'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.AddField(
17
+            model_name='bookingtable',
18
+            name='owner',
19
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
20
+        ),
21
+        migrations.AddField(
22
+            model_name='ingredient',
23
+            name='owner',
24
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
25
+        ),
26
+        migrations.AddField(
27
+            model_name='menufile',
28
+            name='owner',
29
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
30
+        ),
31
+        migrations.AddField(
32
+            model_name='menuitem',
33
+            name='owner',
34
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
35
+        ),
36
+        migrations.AddField(
37
+            model_name='order',
38
+            name='owner',
39
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
40
+        ),
41
+        migrations.AddField(
42
+            model_name='orderitem',
43
+            name='owner',
44
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
45
+        ),
46
+        migrations.AddField(
47
+            model_name='setting',
48
+            name='owner',
49
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
50
+        ),
51
+        migrations.AddField(
52
+            model_name='store',
53
+            name='owner',
54
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
55
+        ),
56
+        migrations.AddField(
57
+            model_name='storefile',
58
+            name='owner',
59
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
60
+        ),
61
+        migrations.AddField(
62
+            model_name='table',
63
+            name='owner',
64
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
65
+        ),
66
+    ]

+ 68 - 0
app/pos/migrations/0018_auto_20220520_2029.py

@@ -0,0 +1,68 @@
1
+# Generated by Django 3.2.13 on 2022-05-20 13:29
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0017_auto_20220519_2146'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='orderitem',
15
+            name='note',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+        migrations.AlterField(
19
+            model_name='bookingtable',
20
+            name='status',
21
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
22
+        ),
23
+        migrations.AlterField(
24
+            model_name='ingredient',
25
+            name='status',
26
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
27
+        ),
28
+        migrations.AlterField(
29
+            model_name='menufile',
30
+            name='status',
31
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
32
+        ),
33
+        migrations.AlterField(
34
+            model_name='menuitem',
35
+            name='status',
36
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
37
+        ),
38
+        migrations.AlterField(
39
+            model_name='order',
40
+            name='status',
41
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
42
+        ),
43
+        migrations.AlterField(
44
+            model_name='orderitem',
45
+            name='status',
46
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
47
+        ),
48
+        migrations.AlterField(
49
+            model_name='setting',
50
+            name='status',
51
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
52
+        ),
53
+        migrations.AlterField(
54
+            model_name='store',
55
+            name='status',
56
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
57
+        ),
58
+        migrations.AlterField(
59
+            model_name='storefile',
60
+            name='status',
61
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
62
+        ),
63
+        migrations.AlterField(
64
+            model_name='table',
65
+            name='status',
66
+            field=models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100),
67
+        ),
68
+    ]

+ 39 - 0
app/pos/migrations/0019_uimenu.py

@@ -0,0 +1,39 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 03:32
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+import mptt.fields
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+        ('pos', '0018_auto_20220520_2029'),
14
+    ]
15
+
16
+    operations = [
17
+        migrations.CreateModel(
18
+            name='UIMenu',
19
+            fields=[
20
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('created_at', models.DateTimeField(auto_now_add=True)),
22
+                ('updated_at', models.DateTimeField(auto_now=True)),
23
+                ('inProcess', models.CharField(blank=True, max_length=100, null=True)),
24
+                ('status', models.CharField(choices=[('process', 'Process'), ('fn', 'Finished'), ('purchase', 'Purchase')], default='process', max_length=100)),
25
+                ('name', models.CharField(max_length=200)),
26
+                ('group', models.CharField(max_length=200)),
27
+                ('url', models.URLField()),
28
+                ('lft', models.PositiveIntegerField(editable=False)),
29
+                ('rght', models.PositiveIntegerField(editable=False)),
30
+                ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
31
+                ('level', models.PositiveIntegerField(editable=False)),
32
+                ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
33
+                ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='pos.uimenu')),
34
+            ],
35
+            options={
36
+                'abstract': False,
37
+            },
38
+        ),
39
+    ]

+ 22 - 0
app/pos/migrations/0020_setting_note.py

@@ -0,0 +1,22 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 04:43
2
+
3
+from django.db import migrations, models
4
+from django.contrib.postgres.operations import HStoreExtension, UnaccentExtension
5
+
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('pos', '0019_uimenu'),
12
+    ]
13
+
14
+    operations = [
15
+        HStoreExtension(),
16
+        UnaccentExtension(),
17
+        migrations.AddField(
18
+            model_name='setting',
19
+            name='note',
20
+            field=models.CharField(blank=True, max_length=200, null=True),
21
+        ),
22
+    ]

+ 19 - 0
app/pos/migrations/0021_alter_setting_data.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 04:45
2
+
3
+import django.contrib.postgres.fields.hstore
4
+from django.db import migrations
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0020_setting_note'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='setting',
16
+            name='data',
17
+            field=django.contrib.postgres.fields.hstore.HStoreField(blank=True, null=True),
18
+        ),
19
+    ]

+ 18 - 0
app/pos/migrations/0022_alter_uimenu_url.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 05:21
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0021_alter_setting_data'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='uimenu',
15
+            name='url',
16
+            field=models.CharField(max_length=200),
17
+        ),
18
+    ]

+ 18 - 0
app/pos/migrations/0023_alter_store_name.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 05:27
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0022_alter_uimenu_url'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='store',
15
+            name='name',
16
+            field=models.CharField(default='Unititled', max_length=100),
17
+        ),
18
+    ]

+ 19 - 0
app/pos/migrations/0024_uimenu_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-21 07:33
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0023_alter_store_name'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='uimenu',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 18 - 0
app/pos/migrations/0025_uimenu_icon.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-22 16:34
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0024_uimenu_store'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='uimenu',
15
+            name='icon',
16
+            field=models.CharField(blank=True, default='file', max_length=100, null=True),
17
+        ),
18
+    ]

+ 19 - 0
app/pos/migrations/0026_order_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-23 05:24
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0025_uimenu_icon'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='order',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pos.store'),
18
+        ),
19
+    ]

+ 19 - 0
app/pos/migrations/0027_orderitem_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-24 04:51
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0026_order_store'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='orderitem',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pos.store'),
18
+        ),
19
+    ]

+ 28 - 0
app/pos/migrations/0028_auto_20220529_1350.py

@@ -0,0 +1,28 @@
1
+# Generated by Django 3.2.13 on 2022-05-29 06:50
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0027_orderitem_store'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='store',
15
+            name='address',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+        migrations.AddField(
19
+            model_name='store',
20
+            name='province',
21
+            field=models.CharField(blank=True, max_length=100, null=True),
22
+        ),
23
+        migrations.AddField(
24
+            model_name='store',
25
+            name='storeType',
26
+            field=models.CharField(blank=True, max_length=100, null=True),
27
+        ),
28
+    ]

+ 40 - 0
app/pos/migrations/0029_auto_20220530_1225.py

@@ -0,0 +1,40 @@
1
+# Generated by Django 3.2.13 on 2022-05-30 05:25
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+import taggit.managers
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        ('taggit', '0005_auto_20220424_2025'),
12
+        ('pos', '0028_auto_20220529_1350'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.RemoveField(
17
+            model_name='menufile',
18
+            name='store',
19
+        ),
20
+        migrations.AddField(
21
+            model_name='menufile',
22
+            name='menuItem',
23
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.menuitem'),
24
+        ),
25
+        migrations.AlterField(
26
+            model_name='menufile',
27
+            name='tags',
28
+            field=taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'),
29
+        ),
30
+        migrations.AlterField(
31
+            model_name='store',
32
+            name='storeType',
33
+            field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Store Type'),
34
+        ),
35
+        migrations.AlterField(
36
+            model_name='storefile',
37
+            name='tags',
38
+            field=taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'),
39
+        ),
40
+    ]

+ 19 - 0
app/pos/migrations/0030_bookingtable_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-30 07:10
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0029_auto_20220530_1225'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='bookingtable',
16
+            name='store',
17
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 23 - 0
app/pos/migrations/0031_auto_20220530_1417.py

@@ -0,0 +1,23 @@
1
+# Generated by Django 3.2.13 on 2022-05-30 07:17
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0030_bookingtable_store'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='bookingtable',
15
+            name='onTime',
16
+            field=models.TimeField(null=True),
17
+        ),
18
+        migrations.AlterField(
19
+            model_name='bookingtable',
20
+            name='onDate',
21
+            field=models.DateField(null=True),
22
+        ),
23
+    ]

+ 135 - 0
app/pos/migrations/0032_auto_20220530_1510.py

@@ -0,0 +1,135 @@
1
+# Generated by Django 3.2.13 on 2022-05-30 08:10
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+import djrichtextfield.models
7
+import mptt.fields
8
+
9
+
10
+class Migration(migrations.Migration):
11
+
12
+    dependencies = [
13
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14
+        ('pos', '0031_auto_20220530_1417'),
15
+    ]
16
+
17
+    operations = [
18
+        migrations.RemoveField(
19
+            model_name='bookingtable',
20
+            name='inProcess',
21
+        ),
22
+        migrations.RemoveField(
23
+            model_name='bookingtable',
24
+            name='status',
25
+        ),
26
+        migrations.RemoveField(
27
+            model_name='ingredient',
28
+            name='inProcess',
29
+        ),
30
+        migrations.RemoveField(
31
+            model_name='ingredient',
32
+            name='status',
33
+        ),
34
+        migrations.RemoveField(
35
+            model_name='menufile',
36
+            name='inProcess',
37
+        ),
38
+        migrations.RemoveField(
39
+            model_name='menufile',
40
+            name='status',
41
+        ),
42
+        migrations.RemoveField(
43
+            model_name='menuitem',
44
+            name='inProcess',
45
+        ),
46
+        migrations.RemoveField(
47
+            model_name='menuitem',
48
+            name='status',
49
+        ),
50
+        migrations.RemoveField(
51
+            model_name='order',
52
+            name='inProcess',
53
+        ),
54
+        migrations.RemoveField(
55
+            model_name='order',
56
+            name='status',
57
+        ),
58
+        migrations.RemoveField(
59
+            model_name='orderitem',
60
+            name='inProcess',
61
+        ),
62
+        migrations.RemoveField(
63
+            model_name='orderitem',
64
+            name='status',
65
+        ),
66
+        migrations.RemoveField(
67
+            model_name='setting',
68
+            name='inProcess',
69
+        ),
70
+        migrations.RemoveField(
71
+            model_name='setting',
72
+            name='status',
73
+        ),
74
+        migrations.RemoveField(
75
+            model_name='store',
76
+            name='inProcess',
77
+        ),
78
+        migrations.RemoveField(
79
+            model_name='store',
80
+            name='status',
81
+        ),
82
+        migrations.RemoveField(
83
+            model_name='storefile',
84
+            name='inProcess',
85
+        ),
86
+        migrations.RemoveField(
87
+            model_name='storefile',
88
+            name='status',
89
+        ),
90
+        migrations.RemoveField(
91
+            model_name='table',
92
+            name='inProcess',
93
+        ),
94
+        migrations.RemoveField(
95
+            model_name='table',
96
+            name='status',
97
+        ),
98
+        migrations.RemoveField(
99
+            model_name='uimenu',
100
+            name='inProcess',
101
+        ),
102
+        migrations.RemoveField(
103
+            model_name='uimenu',
104
+            name='status',
105
+        ),
106
+        migrations.CreateModel(
107
+            name='PostCategory',
108
+            fields=[
109
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
110
+                ('name', models.CharField(max_length=200)),
111
+                ('lft', models.PositiveIntegerField(editable=False)),
112
+                ('rght', models.PositiveIntegerField(editable=False)),
113
+                ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
114
+                ('level', models.PositiveIntegerField(editable=False)),
115
+                ('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='pos.postcategory')),
116
+            ],
117
+            options={
118
+                'abstract': False,
119
+            },
120
+        ),
121
+        migrations.CreateModel(
122
+            name='Post',
123
+            fields=[
124
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
125
+                ('created_at', models.DateTimeField(auto_now_add=True)),
126
+                ('updated_at', models.DateTimeField(auto_now=True)),
127
+                ('title', models.CharField(max_length=200)),
128
+                ('content', djrichtextfield.models.RichTextField()),
129
+                ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
130
+            ],
131
+            options={
132
+                'abstract': False,
133
+            },
134
+        ),
135
+    ]

+ 19 - 0
app/pos/migrations/0033_post_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-30 08:29
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0032_auto_20220530_1510'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='post',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 31 - 0
app/pos/migrations/0034_auto_20220531_2134.py

@@ -0,0 +1,31 @@
1
+# Generated by Django 3.2.13 on 2022-05-31 14:34
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+import djrichtextfield.models
6
+import mptt.fields
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        ('pos', '0033_post_store'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.AddField(
17
+            model_name='post',
18
+            name='category',
19
+            field=mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pos.postcategory'),
20
+        ),
21
+        migrations.AddField(
22
+            model_name='post',
23
+            name='featureImage',
24
+            field=models.ImageField(blank=True, height_field=800, null=True, upload_to='uploads/%Y/%m/%d/', width_field=450),
25
+        ),
26
+        migrations.AlterField(
27
+            model_name='post',
28
+            name='content',
29
+            field=djrichtextfield.models.RichTextField(blank=True),
30
+        ),
31
+    ]

+ 23 - 0
app/pos/migrations/0035_auto_20220531_2151.py

@@ -0,0 +1,23 @@
1
+# Generated by Django 3.2.13 on 2022-05-31 14:51
2
+
3
+from django.db import migrations
4
+import mptt.fields
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0034_auto_20220531_2134'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.RemoveField(
15
+            model_name='post',
16
+            name='category',
17
+        ),
18
+        migrations.AddField(
19
+            model_name='post',
20
+            name='category',
21
+            field=mptt.fields.TreeManyToManyField(blank=True, null=True, to='pos.PostCategory'),
22
+        ),
23
+    ]

+ 18 - 0
app/pos/migrations/0036_alter_post_featureimage.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-05-31 15:01
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0035_auto_20220531_2151'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='post',
15
+            name='featureImage',
16
+            field=models.ImageField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+    ]

+ 19 - 0
app/pos/migrations/0037_post_photos.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-05-31 15:06
2
+
3
+import django.contrib.postgres.fields
4
+from django.db import migrations, models
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0036_alter_post_featureimage'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='post',
16
+            name='photos',
17
+            field=django.contrib.postgres.fields.ArrayField(base_field=models.ImageField(upload_to='uploads/%Y/%m/%d/'), blank=True, null=True, size=None),
18
+        ),
19
+    ]

+ 37 - 0
app/pos/migrations/0038_auto_20220531_2208.py

@@ -0,0 +1,37 @@
1
+# Generated by Django 3.2.13 on 2022-05-31 15:08
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+import taggit.managers
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+        ('taggit', '0005_auto_20220424_2025'),
14
+        ('pos', '0037_post_photos'),
15
+    ]
16
+
17
+    operations = [
18
+        migrations.RemoveField(
19
+            model_name='post',
20
+            name='photos',
21
+        ),
22
+        migrations.CreateModel(
23
+            name='PostFile',
24
+            fields=[
25
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
26
+                ('created_at', models.DateTimeField(auto_now_add=True)),
27
+                ('updated_at', models.DateTimeField(auto_now=True)),
28
+                ('file', models.FileField(upload_to='uploads/%Y/%m/%d/')),
29
+                ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
30
+                ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pos.post')),
31
+                ('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
32
+            ],
33
+            options={
34
+                'abstract': False,
35
+            },
36
+        ),
37
+    ]

+ 20 - 0
app/pos/migrations/0039_post_tags.py

@@ -0,0 +1,20 @@
1
+# Generated by Django 3.2.13 on 2022-06-01 07:23
2
+
3
+from django.db import migrations
4
+import taggit.managers
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('taggit', '0005_auto_20220424_2025'),
11
+        ('pos', '0038_auto_20220531_2208'),
12
+    ]
13
+
14
+    operations = [
15
+        migrations.AddField(
16
+            model_name='post',
17
+            name='tags',
18
+            field=taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'),
19
+        ),
20
+    ]

+ 18 - 0
app/pos/migrations/0040_post_description.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-01 07:36
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0039_post_tags'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='post',
15
+            name='description',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+    ]

+ 32 - 0
app/pos/migrations/0041_customer.py

@@ -0,0 +1,32 @@
1
+# Generated by Django 3.2.13 on 2022-06-01 07:41
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    dependencies = [
11
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12
+        ('pos', '0040_post_description'),
13
+    ]
14
+
15
+    operations = [
16
+        migrations.CreateModel(
17
+            name='Customer',
18
+            fields=[
19
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20
+                ('created_at', models.DateTimeField(auto_now_add=True)),
21
+                ('updated_at', models.DateTimeField(auto_now=True)),
22
+                ('fullName', models.CharField(max_length=200)),
23
+                ('email', models.EmailField(blank=True, max_length=254, null=True)),
24
+                ('lineId', models.CharField(blank=True, max_length=100, null=True)),
25
+                ('gender', models.CharField(choices=[('na', 'N/A'), ('lgbt', 'LGBT'), ('male', 'Male'), ('female', 'Female')], default='na', max_length=40)),
26
+                ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
27
+            ],
28
+            options={
29
+                'abstract': False,
30
+            },
31
+        ),
32
+    ]

+ 19 - 0
app/pos/migrations/0042_customer_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-06-01 08:19
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0041_customer'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='customer',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 32 - 0
app/pos/migrations/0043_code.py

@@ -0,0 +1,32 @@
1
+# Generated by Django 3.2.13 on 2022-06-02 14:02
2
+
3
+from django.conf import settings
4
+from django.db import migrations, models
5
+import django.db.models.deletion
6
+import django_editorjs_fields.fields
7
+
8
+
9
+class Migration(migrations.Migration):
10
+
11
+    dependencies = [
12
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+        ('pos', '0042_customer_store'),
14
+    ]
15
+
16
+    operations = [
17
+        migrations.CreateModel(
18
+            name='Code',
19
+            fields=[
20
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21
+                ('created_at', models.DateTimeField(auto_now_add=True)),
22
+                ('updated_at', models.DateTimeField(auto_now=True)),
23
+                ('body_default', models.TextField()),
24
+                ('body_editorjs', django_editorjs_fields.fields.EditorJsJSONField()),
25
+                ('body_editorjs_text', django_editorjs_fields.fields.EditorJsTextField()),
26
+                ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
27
+            ],
28
+            options={
29
+                'abstract': False,
30
+            },
31
+        ),
32
+    ]

+ 24 - 0
app/pos/migrations/0044_auto_20220603_1058.py

@@ -0,0 +1,24 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 03:58
2
+
3
+from django.db import migrations
4
+import filebrowser.fields
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0043_code'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='code',
16
+            name='document',
17
+            field=filebrowser.fields.FileBrowseField(blank=True, max_length=200, verbose_name='PDF'),
18
+        ),
19
+        migrations.AddField(
20
+            model_name='code',
21
+            name='image',
22
+            field=filebrowser.fields.FileBrowseField(blank=True, max_length=200, verbose_name='Image'),
23
+        ),
24
+    ]

+ 18 - 0
app/pos/migrations/0045_code_code.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 04:35
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0044_auto_20220603_1058'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='code',
15
+            name='code',
16
+            field=models.TextField(blank=True),
17
+        ),
18
+    ]

+ 48 - 0
app/pos/migrations/0046_auto_20220603_1258.py

@@ -0,0 +1,48 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 05:58
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0045_code_code'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.RenameField(
14
+            model_name='code',
15
+            old_name='code',
16
+            new_name='cssCode',
17
+        ),
18
+        migrations.RemoveField(
19
+            model_name='code',
20
+            name='body_default',
21
+        ),
22
+        migrations.RemoveField(
23
+            model_name='code',
24
+            name='body_editorjs',
25
+        ),
26
+        migrations.RemoveField(
27
+            model_name='code',
28
+            name='body_editorjs_text',
29
+        ),
30
+        migrations.RemoveField(
31
+            model_name='code',
32
+            name='document',
33
+        ),
34
+        migrations.RemoveField(
35
+            model_name='code',
36
+            name='image',
37
+        ),
38
+        migrations.AddField(
39
+            model_name='code',
40
+            name='jsCode',
41
+            field=models.TextField(blank=True),
42
+        ),
43
+        migrations.AddField(
44
+            model_name='code',
45
+            name='pluginCode',
46
+            field=models.TextField(blank=True),
47
+        ),
48
+    ]

+ 19 - 0
app/pos/migrations/0047_code_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 06:07
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0046_auto_20220603_1258'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='code',
16
+            name='store',
17
+            field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 19 - 0
app/pos/migrations/0048_alter_code_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 06:15
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0047_code_store'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AlterField(
15
+            model_name='code',
16
+            name='store',
17
+            field=models.OneToOneField(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 18 - 0
app/pos/migrations/0049_uimenu_norder.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 08:01
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0048_alter_code_store'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='uimenu',
15
+            name='nOrder',
16
+            field=models.IntegerField(default=1),
17
+        ),
18
+    ]

+ 19 - 0
app/pos/migrations/0050_profile_store.py

@@ -0,0 +1,19 @@
1
+# Generated by Django 3.2.13 on 2022-06-03 13:47
2
+
3
+from django.db import migrations, models
4
+import django.db.models.deletion
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0049_uimenu_norder'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='profile',
16
+            name='store',
17
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='pos.store'),
18
+        ),
19
+    ]

+ 18 - 0
app/pos/migrations/0051_menuitem_qrcode.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-05 17:25
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0050_profile_store'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='menuitem',
15
+            name='qrCode',
16
+            field=models.BinaryField(blank=True, null=True),
17
+        ),
18
+    ]

+ 18 - 0
app/pos/migrations/0052_alter_menuitem_qrcode.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-05 17:59
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0051_menuitem_qrcode'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='menuitem',
15
+            name='qrCode',
16
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+    ]

+ 23 - 0
app/pos/migrations/0053_auto_20220606_1058.py

@@ -0,0 +1,23 @@
1
+# Generated by Django 3.2.13 on 2022-06-06 03:58
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0052_alter_menuitem_qrcode'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='order',
15
+            name='qrCode',
16
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+        migrations.AddField(
19
+            model_name='store',
20
+            name='qrCode',
21
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
22
+        ),
23
+    ]

+ 23 - 0
app/pos/migrations/0054_auto_20220606_1336.py

@@ -0,0 +1,23 @@
1
+# Generated by Django 3.2.13 on 2022-06-06 06:36
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0053_auto_20220606_1058'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='bookingtable',
15
+            name='qrCode',
16
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+        migrations.AddField(
19
+            model_name='table',
20
+            name='qrCode',
21
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
22
+        ),
23
+    ]

+ 18 - 0
app/pos/migrations/0055_customer_qrcode.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-06 06:41
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0054_auto_20220606_1336'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='customer',
15
+            name='qrCode',
16
+            field=models.FileField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+    ]

+ 24 - 0
app/pos/migrations/0056_auto_20220606_1348.py

@@ -0,0 +1,24 @@
1
+# Generated by Django 3.2.13 on 2022-06-06 06:48
2
+
3
+from django.db import migrations
4
+import django_google_maps.fields
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('pos', '0055_customer_qrcode'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='store',
16
+            name='geolocation',
17
+            field=django_google_maps.fields.GeoLocationField(blank=True, max_length=100, null=True),
18
+        ),
19
+        migrations.AlterField(
20
+            model_name='store',
21
+            name='address',
22
+            field=django_google_maps.fields.AddressField(blank=True, max_length=100, null=True),
23
+        ),
24
+    ]

+ 18 - 0
app/pos/migrations/0057_store_addresstext.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-06 06:50
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0056_auto_20220606_1348'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='store',
15
+            name='addressText',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+    ]

+ 18 - 0
app/pos/migrations/0058_post_relatemenus.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-11 13:18
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0057_store_addresstext'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='post',
15
+            name='relateMenus',
16
+            field=models.ManyToManyField(blank=True, null=True, to='pos.MenuItem'),
17
+        ),
18
+    ]

+ 18 - 0
app/pos/migrations/0059_menuitem_featureimage.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-11 16:17
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0058_post_relatemenus'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='menuitem',
15
+            name='featureImage',
16
+            field=models.ImageField(blank=True, null=True, upload_to='uploads/%Y/%m/%d/'),
17
+        ),
18
+    ]

+ 18 - 0
app/pos/migrations/0060_menuitem_description.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.13 on 2022-06-12 05:51
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('pos', '0059_menuitem_featureimage'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='menuitem',
15
+            name='description',
16
+            field=models.TextField(blank=True, null=True),
17
+        ),
18
+    ]

+ 0 - 0
app/pos/migrations/0061_store_logo.py


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików

tum/soc - Gogs: Simplico Git Service

Нет описания

post_init.py 106KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743
  1. # IRIS Source Code
  2. # Copyright (C) 2021 - Airbus CyberSecurity (SAS)
  3. # ir@cyberactionlab.net
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU Lesser General Public
  7. # License as published by the Free Software Foundation; either
  8. # version 3 of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this program; if not, write to the Free Software Foundation,
  17. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. import json
  19. from pathlib import Path
  20. import glob
  21. import os
  22. import random
  23. import secrets
  24. import string
  25. import socket
  26. import time
  27. from alembic import command
  28. from alembic.config import Config
  29. from sqlalchemy import create_engine, exc, or_, text
  30. from sqlalchemy_utils import create_database
  31. from sqlalchemy_utils import database_exists
  32. from app import app
  33. from app import bc
  34. from app import celery
  35. from app import db
  36. from app.datamgmt.iris_engine.modules_db import iris_module_disable_by_id
  37. from app.datamgmt.manage.manage_groups_db import add_case_access_to_group
  38. from app.datamgmt.manage.manage_users_db import add_user_to_group
  39. from app.datamgmt.manage.manage_users_db import add_user_to_organisation
  40. from app.iris_engine.access_control.utils import ac_add_user_effective_access
  41. from app.iris_engine.demo_builder import create_demo_cases
  42. from app.iris_engine.access_control.utils import ac_get_mask_analyst
  43. from app.datamgmt.manage.manage_groups_db import get_group_by_name
  44. from app.iris_engine.access_control.utils import ac_get_mask_full_permissions
  45. from app.iris_engine.module_handler.module_handler import check_module_health
  46. from app.iris_engine.module_handler.module_handler import instantiate_module_from_name
  47. from app.iris_engine.module_handler.module_handler import register_module
  48. from app.models.models import create_safe_limited
  49. from app.models.alerts import Severity, AlertStatus, AlertResolutionStatus
  50. from app.models.authorization import CaseAccessLevel
  51. from app.models.authorization import Group
  52. from app.models.authorization import Organisation
  53. from app.models.authorization import User
  54. from app.models.cases import Cases, CaseState
  55. from app.models.cases import Client
  56. from app.models.models import AnalysisStatus, CaseClassification, ReviewStatus, ReviewStatusList, EvidenceTypes
  57. from app.models.models import AssetsType
  58. from app.models.models import EventCategory
  59. from app.models.models import IocType
  60. from app.models.models import IrisHook
  61. from app.models.models import IrisModule
  62. from app.models.models import Languages
  63. from app.models.models import OsType
  64. from app.models.models import ReportType
  65. from app.models.models import ServerSettings
  66. from app.models.models import TaskStatus
  67. from app.models.models import Tlp
  68. from app.models.models import create_safe
  69. from app.models.models import create_safe_attr
  70. from app.models.models import get_by_value_or_create
  71. from app.models.models import get_or_create
  72. from app.iris_engine.demo_builder import create_demo_users
  73. log = app.logger
  74. # Get the database host and port from environment variables
  75. db_host = app.config.get('PG_SERVER')
  76. db_port = int(app.config.get('PG_PORT'))
  77. # Get the retry parameters from environment variables
  78. retry_count = int(app.config.get('DB_RETRY_COUNT'))
  79. retry_delay = int(app.config.get('DB_RETRY_DELAY'))
  80. def connect_to_database(host: str, port: int) -> bool:
  81. """Attempts to connect to a database at the specified host and port.
  82. Args:
  83. host: A string representing the hostname or IP address of the database server.
  84. port: An integer representing the port number to connect to.
  85. Returns:
  86. A boolean value indicating whether the connection was successful.
  87. """
  88. # Create a new socket object
  89. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  90. try:
  91. # Try to connect to the database
  92. s.connect((host, port))
  93. # If the connection was successful, close the socket and return True
  94. s.close()
  95. return True
  96. except socket.error:
  97. # If the connection failed, close the socket and return False
  98. s.close()
  99. return False
  100. def run_post_init(development=False):
  101. """Runs post-initiation steps for the IRIS application.
  102. Args:
  103. development: A boolean value indicating whether the application is running in development mode.
  104. """
  105. # Log the IRIS version and post-initiation steps
  106. log.info(f'IRIS {app.config.get("IRIS_VERSION")}')
  107. log.info("Running post initiation steps")
  108. if os.getenv("IRIS_WORKER") is None:
  109. create_directories()
  110. # Attempt to connect to the database with retries
  111. log.info("Attempting to connect to the database...")
  112. for i in range(retry_count):
  113. log.info("Connecting to database, attempt " + str(i+1) + "/" + str(retry_count))
  114. conn = connect_to_database(db_host, db_port)
  115. if conn:
  116. break
  117. log.info("Retrying in " + str(retry_delay) + "seconds...")
  118. time.sleep(retry_delay)
  119. # If the connection is still not established, exit the script
  120. if not conn:
  121. log.info("Failed to connect to database after " + str(retry_count) + " attempts.")
  122. exit(1)
  123. # Setup database before everything
  124. #log.info("Adding pgcrypto extension")
  125. #pg_add_pgcrypto_ext()
  126. # Setup database before everything
  127. with app.app_context():
  128. log.info("Creating all Iris tables")
  129. db.create_all(bind_key=None)
  130. db.session.commit()
  131. log.info("Creating Celery metatasks tables")
  132. create_safe_db(db_name="iris_tasks")
  133. db.create_all(bind_key="iris_tasks")
  134. db.session.commit()
  135. log.info("Running DB migration")
  136. alembic_cfg = Config(file_='app/alembic.ini')
  137. alembic_cfg.set_main_option('sqlalchemy.url', app.config['SQLALCHEMY_DATABASE_URI'])
  138. command.upgrade(alembic_cfg, 'head')
  139. # Create base server settings if they don't exist
  140. srv_settings = ServerSettings.query.first()
  141. if srv_settings is None:
  142. log.info("Creating base server settings")
  143. create_safe_server_settings()
  144. srv_settings = ServerSettings.query.first()
  145. prevent_objects = srv_settings.prevent_post_objects_repush
  146. # Create base languages, OS types, IOC types, attributes, report types, TLP, event categories, assets,
  147. # analysis status, case classification, task status, severities, alert status, case states, and hooks
  148. log.info("Creating base languages")
  149. create_safe_languages()
  150. log.info("Creating base os types")
  151. create_safe_os_types()
  152. if not prevent_objects:
  153. log.info("Creating base IOC types")
  154. create_safe_ioctypes()
  155. log.info("Creating base attributes")
  156. create_safe_attributes()
  157. log.info("Creating base report types")
  158. create_safe_report_types()
  159. log.info("Creating base TLP")
  160. create_safe_tlp()
  161. log.info("Creating base events categories")
  162. create_safe_events_cats()
  163. if not prevent_objects:
  164. log.info("Creating base assets")
  165. create_safe_assets()
  166. log.info("Creating base analysis status")
  167. create_safe_analysis_status()
  168. if not prevent_objects:
  169. log.info("Creating base case classification")
  170. create_safe_classifications()
  171. log.info("Creating base tasks status")
  172. create_safe_task_status()
  173. log.info("Creating base severities")
  174. create_safe_severities()
  175. log.info("Creating base alert status")
  176. create_safe_alert_status()
  177. log.info("Creating base evidence types")
  178. create_safe_evidence_types()
  179. log.info("Creating base alert resolution status")
  180. create_safe_alert_resolution_status()
  181. if not prevent_objects:
  182. log.info("Creating base case states")
  183. create_safe_case_states()
  184. log.info("Creating base review status")
  185. create_safe_review_status()
  186. log.info("Creating base hooks")
  187. create_safe_hooks()
  188. # Create initial authorization model, administrative user, and customer
  189. log.info("Creating initial authorisation model")
  190. def_org, gadm, ganalysts = create_safe_auth_model()
  191. log.info("Creating first administrative user")
  192. admin, pwd = create_safe_admin(def_org=def_org, gadm=gadm)
  193. if not srv_settings.prevent_post_mod_repush:
  194. log.info("Registering default modules")
  195. register_default_modules()
  196. log.info("Creating initial customer")
  197. client = create_safe_client()
  198. log.info("Creating initial case")
  199. create_safe_case(
  200. user=admin,
  201. client=client,
  202. groups=[gadm, ganalysts]
  203. )
  204. # Setup symlinks for custom_assets
  205. log.info("Creating symlinks for custom asset icons")
  206. custom_assets_symlinks()
  207. # If demo mode is enabled, create demo users and cases
  208. if app.config.get('DEMO_MODE_ENABLED') == 'True':
  209. log.warning("============================")
  210. log.warning("| THIS IS DEMO INSTANCE |")
  211. log.warning("| DO NOT USE IN PRODUCTION |")
  212. log.warning("============================")
  213. users_data = create_demo_users(def_org, gadm, ganalysts,
  214. int(app.config.get('DEMO_USERS_COUNT', 10)),
  215. app.config.get('DEMO_USERS_SEED'),
  216. int(app.config.get('DEMO_ADM_COUNT', 4)),
  217. app.config.get('DEMO_ADM_SEED'))
  218. create_demo_cases(users_data=users_data,
  219. cases_count=int(app.config.get('DEMO_CASES_COUNT', 20)),
  220. clients_count=int(app.config.get('DEMO_CLIENTS_COUNT', 4)))
  221. # Log completion message
  222. log.info("Post-init steps completed")
  223. log.warning("===============================")
  224. log.warning(f"| IRIS IS READY on port {os.getenv('INTERFACE_HTTPS_PORT')} |")
  225. log.warning("===============================")
  226. # If an administrative user was created, log their credentials
  227. if pwd is not None:
  228. log.info(f'You can now login with user {admin.user} and password >>> {pwd} <<< '
  229. f'on {os.getenv("INTERFACE_HTTPS_PORT")}')
  230. def create_safe_db(db_name):
  231. """Creates a new database with the specified name if it does not already exist.
  232. Args:
  233. db_name: A string representing the name of the database to create.
  234. """
  235. # Create a new engine object for the specified database
  236. engine = create_engine(app.config["SQALCHEMY_PIGGER_URI"] + db_name)
  237. # Check if the database already exists
  238. if not database_exists(engine.url):
  239. # If the database does not exist, create it
  240. create_database(engine.url)
  241. # Dispose of the engine object
  242. engine.dispose()
  243. def create_safe_hooks():
  244. # --- Alert
  245. create_safe(db.session, IrisHook, hook_name='on_postload_alert_create',
  246. hook_description='Triggered on alert creation, after commit in DB')
  247. create_safe(db.session, IrisHook, hook_name='on_postload_alert_delete',
  248. hook_description='Triggered on alert deletion, after commit in DB')
  249. create_safe(db.session, IrisHook, hook_name='on_postload_alert_update',
  250. hook_description='Triggered on alert update, after commit in DB')
  251. create_safe(db.session, IrisHook, hook_name='on_postload_alert_resolution_update',
  252. hook_description='Triggered on alert resolution update, after commit in DB')
  253. create_safe(db.session, IrisHook, hook_name='on_postload_alert_status_update',
  254. hook_description='Triggered on alert status update, after commit in DB')
  255. create_safe(db.session, IrisHook, hook_name='on_postload_alert_escalate',
  256. hook_description='Triggered on alert escalation, after commit in DB')
  257. create_safe(db.session, IrisHook, hook_name='on_postload_alert_merge',
  258. hook_description='Triggered on alert merge, after commit in DB')
  259. create_safe(db.session, IrisHook, hook_name='on_postload_alert_unmerge',
  260. hook_description='Triggered on alert unmerge, after commit in DB')
  261. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_alert',
  262. hook_description='Triggered upon user action')
  263. # --- Case
  264. create_safe(db.session, IrisHook, hook_name='on_preload_case_create',
  265. hook_description='Triggered on case creation, before commit in DB')
  266. create_safe(db.session, IrisHook, hook_name='on_postload_case_create',
  267. hook_description='Triggered on case creation, after commit in DB')
  268. create_safe(db.session, IrisHook, hook_name='on_preload_case_delete',
  269. hook_description='Triggered on case deletion, before commit in DB')
  270. create_safe(db.session, IrisHook, hook_name='on_postload_case_delete',
  271. hook_description='Triggered on case deletion, after commit in DB')
  272. create_safe(db.session, IrisHook, hook_name='on_postload_case_update',
  273. hook_description='Triggered on case update, after commit in DB')
  274. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_case',
  275. hook_description='Triggered upon user action')
  276. # --- Assets
  277. create_safe(db.session, IrisHook, hook_name='on_preload_asset_create',
  278. hook_description='Triggered on asset creation, before commit in DB')
  279. create_safe(db.session, IrisHook, hook_name='on_postload_asset_create',
  280. hook_description='Triggered on asset creation, after commit in DB')
  281. create_safe(db.session, IrisHook, hook_name='on_preload_asset_update',
  282. hook_description='Triggered on asset update, before commit in DB')
  283. create_safe(db.session, IrisHook, hook_name='on_postload_asset_update',
  284. hook_description='Triggered on asset update, after commit in DB')
  285. create_safe(db.session, IrisHook, hook_name='on_preload_asset_delete',
  286. hook_description='Triggered on asset deletion, before commit in DB')
  287. create_safe(db.session, IrisHook, hook_name='on_postload_asset_delete',
  288. hook_description='Triggered on asset deletion, after commit in DB')
  289. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_asset',
  290. hook_description='Triggered upon user action')
  291. # --- Notes
  292. create_safe(db.session, IrisHook, hook_name='on_preload_note_create',
  293. hook_description='Triggered on note creation, before commit in DB')
  294. create_safe(db.session, IrisHook, hook_name='on_postload_note_create',
  295. hook_description='Triggered on note creation, after commit in DB')
  296. create_safe(db.session, IrisHook, hook_name='on_preload_note_update',
  297. hook_description='Triggered on note update, before commit in DB')
  298. create_safe(db.session, IrisHook, hook_name='on_postload_note_update',
  299. hook_description='Triggered on note update, after commit in DB')
  300. create_safe(db.session, IrisHook, hook_name='on_preload_note_delete',
  301. hook_description='Triggered on note deletion, before commit in DB')
  302. create_safe(db.session, IrisHook, hook_name='on_postload_note_delete',
  303. hook_description='Triggered on note deletion, after commit in DB')
  304. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_note',
  305. hook_description='Triggered upon user action')
  306. # --- iocs
  307. create_safe(db.session, IrisHook, hook_name='on_preload_ioc_create',
  308. hook_description='Triggered on ioc creation, before commit in DB')
  309. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_create',
  310. hook_description='Triggered on ioc creation, after commit in DB')
  311. create_safe(db.session, IrisHook, hook_name='on_preload_ioc_update',
  312. hook_description='Triggered on ioc update, before commit in DB')
  313. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_update',
  314. hook_description='Triggered on ioc update, after commit in DB')
  315. create_safe(db.session, IrisHook, hook_name='on_preload_ioc_delete',
  316. hook_description='Triggered on ioc deletion, before commit in DB')
  317. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_delete',
  318. hook_description='Triggered on ioc deletion, after commit in DB')
  319. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_ioc',
  320. hook_description='Triggered upon user action')
  321. # --- events
  322. create_safe(db.session, IrisHook, hook_name='on_preload_event_create',
  323. hook_description='Triggered on event creation, before commit in DB')
  324. create_safe(db.session, IrisHook, hook_name='on_postload_event_create',
  325. hook_description='Triggered on event creation, after commit in DB')
  326. create_safe(db.session, IrisHook, hook_name='on_preload_event_duplicate',
  327. hook_description='Triggered on event duplication, before commit in DB')
  328. create_safe(db.session, IrisHook, hook_name='on_preload_event_update',
  329. hook_description='Triggered on event update, before commit in DB')
  330. create_safe(db.session, IrisHook, hook_name='on_postload_event_update',
  331. hook_description='Triggered on event update, after commit in DB')
  332. create_safe(db.session, IrisHook, hook_name='on_preload_event_delete',
  333. hook_description='Triggered on event deletion, before commit in DB')
  334. create_safe(db.session, IrisHook, hook_name='on_postload_event_delete',
  335. hook_description='Triggered on event deletion, after commit in DB')
  336. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_event',
  337. hook_description='Triggered upon user action')
  338. # --- evidence
  339. create_safe(db.session, IrisHook, hook_name='on_preload_evidence_create',
  340. hook_description='Triggered on evidence creation, before commit in DB')
  341. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_create',
  342. hook_description='Triggered on evidence creation, after commit in DB')
  343. create_safe(db.session, IrisHook, hook_name='on_preload_evidence_update',
  344. hook_description='Triggered on evidence update, before commit in DB')
  345. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_update',
  346. hook_description='Triggered on evidence update, after commit in DB')
  347. create_safe(db.session, IrisHook, hook_name='on_preload_evidence_delete',
  348. hook_description='Triggered on evidence deletion, before commit in DB')
  349. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_delete',
  350. hook_description='Triggered on evidence deletion, after commit in DB')
  351. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_evidence',
  352. hook_description='Triggered upon user action')
  353. # --- tasks
  354. create_safe(db.session, IrisHook, hook_name='on_preload_task_create',
  355. hook_description='Triggered on task creation, before commit in DB')
  356. create_safe(db.session, IrisHook, hook_name='on_postload_task_create',
  357. hook_description='Triggered on task creation, after commit in DB')
  358. create_safe(db.session, IrisHook, hook_name='on_preload_task_update',
  359. hook_description='Triggered on task update, before commit in DB')
  360. create_safe(db.session, IrisHook, hook_name='on_postload_task_update',
  361. hook_description='Triggered on task update, after commit in DB')
  362. create_safe(db.session, IrisHook, hook_name='on_preload_task_delete',
  363. hook_description='Triggered on task deletion, before commit in DB')
  364. create_safe(db.session, IrisHook, hook_name='on_postload_task_delete',
  365. hook_description='Triggered on task deletion, after commit in DB')
  366. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_task',
  367. hook_description='Triggered upon user action')
  368. # --- global tasks
  369. create_safe(db.session, IrisHook, hook_name='on_preload_global_task_create',
  370. hook_description='Triggered on global task creation, before commit in DB')
  371. create_safe(db.session, IrisHook, hook_name='on_postload_global_task_create',
  372. hook_description='Triggered on global task creation, after commit in DB')
  373. create_safe(db.session, IrisHook, hook_name='on_preload_global_task_update',
  374. hook_description='Triggered on task update, before commit in DB')
  375. create_safe(db.session, IrisHook, hook_name='on_postload_global_task_update',
  376. hook_description='Triggered on global task update, after commit in DB')
  377. create_safe(db.session, IrisHook, hook_name='on_preload_global_task_delete',
  378. hook_description='Triggered on task deletion, before commit in DB')
  379. create_safe(db.session, IrisHook, hook_name='on_postload_global_task_delete',
  380. hook_description='Triggered on global task deletion, after commit in DB')
  381. create_safe(db.session, IrisHook, hook_name='on_manual_trigger_global_task',
  382. hook_description='Triggered upon user action')
  383. # --- reports
  384. create_safe(db.session, IrisHook, hook_name='on_preload_report_create',
  385. hook_description='Triggered on report creation, before generation in DB')
  386. create_safe(db.session, IrisHook, hook_name='on_postload_report_create',
  387. hook_description='Triggered on report creation, before download of the document')
  388. create_safe(db.session, IrisHook, hook_name='on_preload_activities_report_create',
  389. hook_description='Triggered on activities report creation, before generation in DB')
  390. create_safe(db.session, IrisHook, hook_name='on_postload_activities_report_create',
  391. hook_description='Triggered on activities report creation, before download of the document')
  392. # --- comments
  393. create_safe(db.session, IrisHook, hook_name='on_postload_asset_commented',
  394. hook_description='Triggered on event commented, after commit in DB')
  395. create_safe(db.session, IrisHook, hook_name='on_postload_asset_comment_update',
  396. hook_description='Triggered on event comment update, after commit in DB')
  397. create_safe(db.session, IrisHook, hook_name='on_postload_asset_comment_delete',
  398. hook_description='Triggered on event comment deletion, after commit in DB')
  399. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_commented',
  400. hook_description='Triggered on evidence commented, after commit in DB')
  401. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_comment_update',
  402. hook_description='Triggered on evidence comment update, after commit in DB')
  403. create_safe(db.session, IrisHook, hook_name='on_postload_evidence_comment_delete',
  404. hook_description='Triggered on evidence comment deletion, after commit in DB')
  405. create_safe(db.session, IrisHook, hook_name='on_postload_task_commented',
  406. hook_description='Triggered on task commented, after commit in DB')
  407. create_safe(db.session, IrisHook, hook_name='on_postload_task_comment_update',
  408. hook_description='Triggered on task comment update, after commit in DB')
  409. create_safe(db.session, IrisHook, hook_name='on_postload_task_comment_delete',
  410. hook_description='Triggered on task comment deletion, after commit in DB')
  411. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_commented',
  412. hook_description='Triggered on IOC commented, after commit in DB')
  413. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_comment_update',
  414. hook_description='Triggered on IOC comment update, after commit in DB')
  415. create_safe(db.session, IrisHook, hook_name='on_postload_ioc_comment_delete',
  416. hook_description='Triggered on IOC comment deletion, after commit in DB')
  417. create_safe(db.session, IrisHook, hook_name='on_postload_event_commented',
  418. hook_description='Triggered on event commented, after commit in DB')
  419. create_safe(db.session, IrisHook, hook_name='on_postload_event_comment_update',
  420. hook_description='Triggered on event comment update, after commit in DB')
  421. create_safe(db.session, IrisHook, hook_name='on_postload_event_comment_delete',
  422. hook_description='Triggered on event comment deletion, after commit in DB')
  423. create_safe(db.session, IrisHook, hook_name='on_postload_note_commented',
  424. hook_description='Triggered on note commented, after commit in DB')
  425. create_safe(db.session, IrisHook, hook_name='on_postload_note_comment_update',
  426. hook_description='Triggered on note comment update, after commit in DB')
  427. create_safe(db.session, IrisHook, hook_name='on_postload_note_comment_delete',
  428. hook_description='Triggered on note comment deletion, after commit in DB')
  429. create_safe(db.session, IrisHook, hook_name='on_postload_alert_commented',
  430. hook_description='Triggered on alert commented, after commit in DB')
  431. create_safe(db.session, IrisHook, hook_name='on_postload_alert_comment_update',
  432. hook_description='Triggered on alert comment update, after commit in DB')
  433. create_safe(db.session, IrisHook, hook_name='on_postload_alert_comment_delete',
  434. hook_description='Triggered on alert comment deletion, after commit in DB')
  435. def pg_add_pgcrypto_ext():
  436. """Adds the pgcrypto extension to the PostgreSQL database.
  437. This extension provides cryptographic functions for PostgreSQL.
  438. """
  439. # Set the application context
  440. with app.app_context():
  441. # Open a connection to the iris_db database
  442. with db.engine.connect() as con:
  443. # Execute a SQL command to create the pgcrypto extension if it does not already exist
  444. con.execute(text('CREATE EXTENSION IF NOT EXISTS pgcrypto CASCADE;'))
  445. db.session.commit()
  446. log.info("pgcrypto extension added")
  447. def create_safe_languages():
  448. """Creates new Language objects if they do not already exist.
  449. This function creates new Language objects with the specified name and code
  450. if they do not already exist in the database.
  451. """
  452. # Create new Language objects for each language
  453. create_safe(db.session, Languages, name="french", code="FR")
  454. create_safe(db.session, Languages, name="english", code="EN")
  455. create_safe(db.session, Languages, name="german", code="DE")
  456. create_safe(db.session, Languages, name="bulgarian", code="BG")
  457. create_safe(db.session, Languages, name="croatian", code="HR")
  458. create_safe(db.session, Languages, name="danish", code="DK")
  459. create_safe(db.session, Languages, name="dutch", code="NL")
  460. create_safe(db.session, Languages, name="estonian", code="EE")
  461. create_safe(db.session, Languages, name="finnish", code="FI")
  462. create_safe(db.session, Languages, name="greek", code="GR")
  463. create_safe(db.session, Languages, name="hungarian", code="HU")
  464. create_safe(db.session, Languages, name="irish", code="IE")
  465. create_safe(db.session, Languages, name="italian", code="IT")
  466. create_safe(db.session, Languages, name="latvian", code="LV")
  467. create_safe(db.session, Languages, name="lithuanian", code="LT")
  468. create_safe(db.session, Languages, name="maltese", code="MT")
  469. create_safe(db.session, Languages, name="polish", code="PL")
  470. create_safe(db.session, Languages, name="portuguese", code="PT")
  471. create_safe(db.session, Languages, name="romanian", code="RO")
  472. create_safe(db.session, Languages, name="slovak", code="SK")
  473. create_safe(db.session, Languages, name="slovenian", code="SI")
  474. create_safe(db.session, Languages, name="spanish", code="ES")
  475. create_safe(db.session, Languages, name="swedish", code="SE")
  476. create_safe(db.session, Languages, name="indian", code="IN")
  477. create_safe(db.session, Languages, name="chinese", code="CN")
  478. create_safe(db.session, Languages, name="korean", code="KR")
  479. create_safe(db.session, Languages, name="arabic", code="AR")
  480. create_safe(db.session, Languages, name="japanese", code="JP")
  481. create_safe(db.session, Languages, name="turkish", code="TR")
  482. create_safe(db.session, Languages, name="vietnamese", code="VN")
  483. create_safe(db.session, Languages, name="thai", code="TH")
  484. create_safe(db.session, Languages, name="hebrew", code="IL")
  485. create_safe(db.session, Languages, name="czech", code="CZ")
  486. create_safe(db.session, Languages, name="norwegian", code="NO")
  487. create_safe(db.session, Languages, name="brazilian", code="BR")
  488. create_safe(db.session, Languages, name="ukrainian", code="UA")
  489. create_safe(db.session, Languages, name="catalan", code="CA")
  490. create_safe(db.session, Languages, name="serbian", code="RS")
  491. create_safe(db.session, Languages, name="persian", code="IR")
  492. create_safe(db.session, Languages, name="afrikaans", code="ZA")
  493. create_safe(db.session, Languages, name="albanian", code="AL")
  494. create_safe(db.session, Languages, name="armenian", code="AM")
  495. def create_safe_events_cats():
  496. """Creates new EventCategory objects if they do not already exist.
  497. This function creates new EventCategory objects with the specified name
  498. if they do not already exist in the database.
  499. """
  500. # Create new EventCategory objects for each category
  501. create_safe(db.session, EventCategory, name="Unspecified")
  502. create_safe(db.session, EventCategory, name="Legitimate")
  503. create_safe(db.session, EventCategory, name="Remediation")
  504. create_safe(db.session, EventCategory, name="Initial Access")
  505. create_safe(db.session, EventCategory, name="Execution")
  506. create_safe(db.session, EventCategory, name="Persistence")
  507. create_safe(db.session, EventCategory, name="Privilege Escalation")
  508. create_safe(db.session, EventCategory, name="Defense Evasion")
  509. create_safe(db.session, EventCategory, name="Credential Access")
  510. create_safe(db.session, EventCategory, name="Discovery")
  511. create_safe(db.session, EventCategory, name="Lateral Movement")
  512. create_safe(db.session, EventCategory, name="Collection")
  513. create_safe(db.session, EventCategory, name="Command and Control")
  514. create_safe(db.session, EventCategory, name="Exfiltration")
  515. create_safe(db.session, EventCategory, name="Impact")
  516. def create_safe_classifications():
  517. """Creates new CaseClassification objects if they do not already exist.
  518. This function reads the MISP classification taxonomy from a JSON file and creates
  519. new CaseClassification objects with the specified name, name_expanded, and description
  520. if they do not already exist in the database.
  521. """
  522. # Read the MISP classification taxonomy from a JSON file
  523. log.info("Reading MISP classification taxonomy from resources/misp.classification.taxonomy.json")
  524. with open(Path(__file__).parent / 'resources' / 'misp.classification.taxonomy.json') as data_file:
  525. data = json.load(data_file)
  526. # Iterate over each classification in the taxonomy
  527. for c in data.get('values'):
  528. predicate = c.get('predicate')
  529. entries = c.get('entry')
  530. # Iterate over each entry in the classification
  531. for entry in entries:
  532. # Create a new CaseClassification object with the specified name, name_expanded, and description
  533. create_safe(db.session, CaseClassification,
  534. name=f"{predicate}:{entry.get('value')}",
  535. name_expanded=f"{predicate.title()}: {entry.get('expanded')}",
  536. description=entry['description'])
  537. def create_safe_analysis_status():
  538. """Creates new AnalysisStatus objects if they do not already exist.
  539. This function creates new AnalysisStatus objects with the specified name
  540. if they do not already exist in the database.
  541. """
  542. # Create new AnalysisStatus objects for each status
  543. create_safe(db.session, AnalysisStatus, name='Unspecified')
  544. create_safe(db.session, AnalysisStatus, name='To be done')
  545. create_safe(db.session, AnalysisStatus, name='Started')
  546. create_safe(db.session, AnalysisStatus, name='Pending')
  547. create_safe(db.session, AnalysisStatus, name='Canceled')
  548. create_safe(db.session, AnalysisStatus, name='Done')
  549. def create_safe_task_status():
  550. """Creates new TaskStatus objects if they do not already exist.
  551. This function creates new TaskStatus objects with the specified status name,
  552. status description, and Bootstrap color if they do not already exist in the database.
  553. """
  554. # Create new TaskStatus objects for each status
  555. create_safe(db.session, TaskStatus, status_name='To do', status_description="", status_bscolor="danger")
  556. create_safe(db.session, TaskStatus, status_name='In progress', status_description="", status_bscolor="warning")
  557. create_safe(db.session, TaskStatus, status_name='On hold', status_description="", status_bscolor="muted")
  558. create_safe(db.session, TaskStatus, status_name='Done', status_description="", status_bscolor="success")
  559. create_safe(db.session, TaskStatus, status_name='Canceled', status_description="", status_bscolor="muted")
  560. def create_safe_severities():
  561. """Creates new Severity objects if they do not already exist.
  562. This function creates new Severity objects with the specified severity name
  563. and severity description if they do not already exist in the database.
  564. """
  565. # Create new Severity objects for each severity level
  566. create_safe(db.session, Severity, severity_name='Unspecified', severity_description="Unspecified")
  567. create_safe(db.session, Severity, severity_name='Informational', severity_description="Informational")
  568. create_safe(db.session, Severity, severity_name='Low', severity_description="Low")
  569. create_safe(db.session, Severity, severity_name='Medium', severity_description="Medium")
  570. create_safe(db.session, Severity, severity_name='High', severity_description="High")
  571. create_safe(db.session, Severity, severity_name='Critical', severity_description="Critical")
  572. def create_safe_alert_status():
  573. """Creates new AlertStatus objects if they do not already exist.
  574. This function creates new AlertStatus objects with the specified status name
  575. and status description if they do not already exist in the database.
  576. """
  577. # Create new AlertStatus objects for each status
  578. create_safe(db.session, AlertStatus, status_name='Unspecified', status_description="Unspecified")
  579. create_safe(db.session, AlertStatus, status_name='New', status_description="Alert is new and unassigned")
  580. create_safe(db.session, AlertStatus, status_name='Assigned', status_description="Alert is assigned to a user and "
  581. "pending investigation")
  582. create_safe(db.session, AlertStatus, status_name='In progress', status_description="Alert is being investigated")
  583. create_safe(db.session, AlertStatus, status_name='Pending', status_description="Alert is in a pending state")
  584. create_safe(db.session, AlertStatus, status_name='Closed', status_description="Alert closed, no action taken")
  585. create_safe(db.session, AlertStatus, status_name='Merged', status_description="Alert merged into an existing case")
  586. create_safe(db.session, AlertStatus, status_name='Escalated', status_description="Alert converted to a new case")
  587. def create_safe_evidence_types():
  588. """Creates new Evidence Types objects if they do not already exist.
  589. This function creates new Evidence Types objects with the specified type name
  590. and type description if they do not already exist in the database.
  591. """
  592. # Create new EvidenceType objects for each status
  593. create_safe(db.session, EvidenceTypes, name='Unspecified', description="Unspecified")
  594. create_safe(db.session, EvidenceTypes, name='HDD image - Generic', description="Generic copy of an hard drive")
  595. create_safe(db.session, EvidenceTypes, name='HDD image - DD - Other', description="DD copy of an hard drive")
  596. create_safe(db.session, EvidenceTypes, name='HDD image - DD - Windows', description="DD copy of an hard drive")
  597. create_safe(db.session, EvidenceTypes, name='HDD image - DD - Unix', description="DD copy of an hard drive")
  598. create_safe(db.session, EvidenceTypes, name='HDD image - DD - MacOS', description="DD copy of an hard drive")
  599. create_safe(db.session, EvidenceTypes, name='HDD image - E01 - Other', description="E01 acquisition of an hard drive")
  600. create_safe(db.session, EvidenceTypes, name='HDD image - E01 - Windows', description="E01 acquisition of an hard drive")
  601. create_safe(db.session, EvidenceTypes, name='HDD image - E01 - Unix', description="E01 acquisition of an hard drive")
  602. create_safe(db.session, EvidenceTypes, name='HDD image - E01 - MacOS', description="E01 acquisition of an hard drive")
  603. create_safe(db.session, EvidenceTypes, name='HDD image - AFF4 - Other', description="AFF4 acquisition of an hard drive")
  604. create_safe(db.session, EvidenceTypes, name='HDD image - AFF4 - Windows', description="AFF4 acquisition of an hard drive")
  605. create_safe(db.session, EvidenceTypes, name='HDD image - AFF4 - Unix', description="AFF4 acquisition of an hard drive")
  606. create_safe(db.session, EvidenceTypes, name='HDD image - AFF4 - MacOS', description="AFF4 acquisition of an hard drive")
  607. create_safe(db.session, EvidenceTypes, name='SSD image - Generic', description="Generic copy of an solid state drive")
  608. create_safe(db.session, EvidenceTypes, name='SSD image - DD - Other', description="DD copy of an solid state drive")
  609. create_safe(db.session, EvidenceTypes, name='SSD image - DD - Windows', description="DD copy of an solid state drive")
  610. create_safe(db.session, EvidenceTypes, name='SSD image - DD - Unix', description="DD copy of an solid state drive")
  611. create_safe(db.session, EvidenceTypes, name='SSD image - DD - MacOS', description="DD copy of an solid state drive")
  612. create_safe(db.session, EvidenceTypes, name='SSD image - E01 - Other', description="EO1 copy of a solid state drive")
  613. create_safe(db.session, EvidenceTypes, name='SSD image - E01 - Windows', description="EO1 copy of a solid state drive")
  614. create_safe(db.session, EvidenceTypes, name='SSD image - E01 - Unix', description="EO1 copy of a solid state drive")
  615. create_safe(db.session, EvidenceTypes, name='SSD image - E01 - MacOS', description="EO1 copy of MacOS on a solid state drive")
  616. create_safe(db.session, EvidenceTypes, name='SSD image - AFF4 - Other', description="AFF4 copy of an solid state drive")
  617. create_safe(db.session, EvidenceTypes, name='SSD image - AFF4 - Windows', description="AFF4 copy of an solid state drive")
  618. create_safe(db.session, EvidenceTypes, name='SSD image - AFF4 - Unix', description="AFF4 copy of an solid state drive")
  619. create_safe(db.session, EvidenceTypes, name='SSD image - AFF4 - MacOS', description="AFF4 copy of an solid state drive")
  620. create_safe(db.session, EvidenceTypes, name='VM image - Generic', description="Generic copy of a VM ")
  621. create_safe(db.session, EvidenceTypes, name='VM image - Linux Server', description="Copy of a Linux Server VM")
  622. create_safe(db.session, EvidenceTypes, name='VM image - Windows Server', description="Copy of a Windows Server VM")
  623. create_safe(db.session, EvidenceTypes, name='VM image - Windows Server', description="Copy of a Windows Server VM")
  624. create_safe(db.session, EvidenceTypes, name='Phone Image - Android', description="Copy of an Android phone")
  625. create_safe(db.session, EvidenceTypes, name='Phone Image - iPhone', description="Copy of an iPhone")
  626. create_safe(db.session, EvidenceTypes, name='Phone backup - Android (adb)', description="adb backup of an Android")
  627. create_safe(db.session, EvidenceTypes, name='Phone backup - iPhone (iTunes)', description="iTunes backup of an iPhone")
  628. create_safe(db.session, EvidenceTypes, name='Tablet Image - Android', description="Copy of an Android tablet")
  629. create_safe(db.session, EvidenceTypes, name='Tablet Image - iPad', description="Copy of an iPad tablet")
  630. create_safe(db.session, EvidenceTypes, name='Tablet backup - Android (adb)', description="adb backup of an Android tablet")
  631. create_safe(db.session, EvidenceTypes, name='Tablet backup - iPad (iTunes)', description="iTunes backup of an iPad")
  632. create_safe(db.session, EvidenceTypes, name='Collection - Velociraptor', description="Velociraptor collection")
  633. create_safe(db.session, EvidenceTypes, name='Collection - ORC', description="ORC collection")
  634. create_safe(db.session, EvidenceTypes, name='Collection - KAPE', description="KAPE collection")
  635. create_safe(db.session, EvidenceTypes, name="Memory acquisition - Physical RAM", description="Physical RAM acquisition")
  636. create_safe(db.session, EvidenceTypes, name="Memory acquisition - VMEM", description="vmem file")
  637. create_safe(db.session, EvidenceTypes, name="Logs - Linux", description="Standard Linux logs")
  638. create_safe(db.session, EvidenceTypes, name="Logs - Windows EVTX", description="Standard Windows EVTX logs")
  639. create_safe(db.session, EvidenceTypes, name="Logs - Windows EVT", description="Standard Windows EVT logs")
  640. create_safe(db.session, EvidenceTypes, name="Logs - MacOS", description="Standard MacOS logs")
  641. create_safe(db.session, EvidenceTypes, name="Logs - Generic", description="Generic logs")
  642. create_safe(db.session, EvidenceTypes, name="Logs - Firewall", description="Firewall logs")
  643. create_safe(db.session, EvidenceTypes, name="Logs - Proxy", description="Proxy logs")
  644. create_safe(db.session, EvidenceTypes, name="Logs - DNS", description="DNS logs")
  645. create_safe(db.session, EvidenceTypes, name="Logs - Email", description="Email logs")
  646. create_safe(db.session, EvidenceTypes, name="Executable - Windows (PE)", description="Generic Windows executable")
  647. create_safe(db.session, EvidenceTypes, name="Executable - Linux (ELF)", description="Generic Linux executable")
  648. create_safe(db.session, EvidenceTypes, name="Executable - MacOS (Mach-O)", description="Generic MacOS executable")
  649. create_safe(db.session, EvidenceTypes, name="Executable - Generic", description="Generic executable")
  650. create_safe(db.session, EvidenceTypes, name="Script - Generic", description="Generic script")
  651. create_safe(db.session, EvidenceTypes, name="Generic - Data blob", description="Generic blob of data")
  652. def create_safe_alert_resolution_status():
  653. """Creates new AlertResolutionStatus objects if they do not already exist.
  654. This function creates new AlertResolutionStatus objects with the specified resolution_status_name
  655. and resolution_status_description if they do not already exist in the database.
  656. """
  657. create_safe(db.session, AlertResolutionStatus, resolution_status_name='False Positive',
  658. resolution_status_description="The alert was a false positive")
  659. create_safe(db.session, AlertResolutionStatus, resolution_status_name='True Positive With Impact',
  660. resolution_status_description="The alert was a true positive and had an impact")
  661. create_safe(db.session, AlertResolutionStatus, resolution_status_name='True Positive Without Impact',
  662. resolution_status_description="The alert was a true positive but had no impact")
  663. create_safe(db.session, AlertResolutionStatus, resolution_status_name='Not Applicable',
  664. resolution_status_description="The alert is not applicable")
  665. create_safe(db.session, AlertResolutionStatus, resolution_status_name='Unknown',
  666. resolution_status_description="Unknown resolution status")
  667. create_safe(db.session, AlertResolutionStatus, resolution_status_name='Legitimate',
  668. resolution_status_description="The alert is acceptable and expected")
  669. def create_safe_case_states():
  670. """Creates new CaseState objects if they do not already exist.
  671. This function creates new CaseState objects with the specified state name,
  672. state description, and protected status if they do not already exist in the database.
  673. """
  674. # Create new CaseState objects for each state
  675. create_safe(db.session, CaseState, state_name='Unspecified', state_description="Unspecified", protected=True)
  676. create_safe(db.session, CaseState, state_name='In progress', state_description="Case is being investigated")
  677. create_safe(db.session, CaseState, state_name='Open', state_description="Case is open", protected=True)
  678. create_safe(db.session, CaseState, state_name='Containment', state_description="Containment is in progress")
  679. create_safe(db.session, CaseState, state_name='Eradication', state_description="Eradication is in progress")
  680. create_safe(db.session, CaseState, state_name='Recovery', state_description="Recovery is in progress")
  681. create_safe(db.session, CaseState, state_name='Post-Incident', state_description="Post-incident phase")
  682. create_safe(db.session, CaseState, state_name='Reporting', state_description="Reporting is in progress")
  683. create_safe(db.session, CaseState, state_name='Closed', state_description="Case is closed", protected=True)
  684. def create_safe_review_status():
  685. """Creates new ReviewStatus objects if they do not already exist.
  686. This function creates new ReviewStatus objects with the specified status name
  687. if they do not already exist in the database.
  688. """
  689. create_safe(db.session, ReviewStatus, status_name=ReviewStatusList.no_review_required)
  690. create_safe(db.session, ReviewStatus, status_name=ReviewStatusList.not_reviewed)
  691. create_safe(db.session, ReviewStatus, status_name=ReviewStatusList.pending_review)
  692. create_safe(db.session, ReviewStatus, status_name=ReviewStatusList.review_in_progress)
  693. create_safe(db.session, ReviewStatus, status_name=ReviewStatusList.reviewed)
  694. def create_safe_assets():
  695. """Creates new AssetsType objects if they do not already exist.
  696. This function creates new AssetsType objects with the specified asset name,
  697. asset description, and asset icons if they do not already exist in the database.
  698. """
  699. # Create new AssetsType objects for each asset type
  700. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Account",
  701. asset_description="Generic Account", asset_icon_not_compromised="user.png",
  702. asset_icon_compromised="ioc_user.png")
  703. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Firewall", asset_description="Firewall",
  704. asset_icon_not_compromised="firewall.png", asset_icon_compromised="ioc_firewall.png")
  705. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Linux - Server",
  706. asset_description="Linux server", asset_icon_not_compromised="server.png",
  707. asset_icon_compromised="ioc_server.png")
  708. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Linux - Computer",
  709. asset_description="Linux computer", asset_icon_not_compromised="desktop.png",
  710. asset_icon_compromised="ioc_desktop.png")
  711. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Linux Account",
  712. asset_description="Linux Account", asset_icon_not_compromised="user.png",
  713. asset_icon_compromised="ioc_user.png")
  714. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Mac - Computer",
  715. asset_description="Mac computer", asset_icon_not_compromised="desktop.png",
  716. asset_icon_compromised="ioc_desktop.png")
  717. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Phone - Android",
  718. asset_description="Android Phone", asset_icon_not_compromised="phone.png",
  719. asset_icon_compromised="ioc_phone.png")
  720. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Phone - IOS",
  721. asset_description="Apple Phone", asset_icon_not_compromised="phone.png",
  722. asset_icon_compromised="ioc_phone.png")
  723. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows - Computer",
  724. asset_description="Standard Windows Computer",
  725. asset_icon_not_compromised="windows_desktop.png",
  726. asset_icon_compromised="ioc_windows_desktop.png")
  727. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows - Server",
  728. asset_description="Standard Windows Server", asset_icon_not_compromised="windows_server.png",
  729. asset_icon_compromised="ioc_windows_server.png")
  730. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows - DC",
  731. asset_description="Domain Controller", asset_icon_not_compromised="windows_server.png",
  732. asset_icon_compromised="ioc_windows_server.png")
  733. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Router", asset_description="Router",
  734. asset_icon_not_compromised="router.png", asset_icon_compromised="ioc_router.png")
  735. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Switch", asset_description="Switch",
  736. asset_icon_not_compromised="switch.png", asset_icon_compromised="ioc_switch.png")
  737. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="VPN", asset_description="VPN",
  738. asset_icon_not_compromised="vpn.png", asset_icon_compromised="ioc_vpn.png")
  739. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="WAF", asset_description="WAF",
  740. asset_icon_not_compromised="firewall.png", asset_icon_compromised="ioc_firewall.png")
  741. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - Local",
  742. asset_description="Windows Account - Local", asset_icon_not_compromised="user.png",
  743. asset_icon_compromised="ioc_user.png")
  744. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - Local - Admin",
  745. asset_description="Windows Account - Local - Admin", asset_icon_not_compromised="user.png",
  746. asset_icon_compromised="ioc_user.png")
  747. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - AD",
  748. asset_description="Windows Account - AD", asset_icon_not_compromised="user.png",
  749. asset_icon_compromised="ioc_user.png")
  750. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - AD - Admin",
  751. asset_description="Windows Account - AD - Admin", asset_icon_not_compromised="user.png",
  752. asset_icon_compromised="ioc_user.png")
  753. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - AD - krbtgt",
  754. asset_description="Windows Account - AD - krbtgt", asset_icon_not_compromised="user.png",
  755. asset_icon_compromised="ioc_user.png")
  756. get_by_value_or_create(db.session, AssetsType, "asset_name", asset_name="Windows Account - AD - Service",
  757. asset_description="Windows Account - AD - krbtgt", asset_icon_not_compromised="user.png",
  758. asset_icon_compromised="ioc_user.png")
  759. def create_safe_client():
  760. """Creates a new Client object if it does not already exist.
  761. This function creates a new Client object with the specified client name
  762. and client description if it does not already exist in the database.
  763. """
  764. # Create a new Client object if it does not already exist
  765. client = get_or_create(db.session, Client,
  766. name="IrisInitialClient")
  767. return client
  768. def create_safe_auth_model():
  769. """Creates new Organisation, Group, and User objects if they do not already exist.
  770. This function creates a new Organisation object with the specified name and description,
  771. and creates new Group objects with the specified name, description, auto-follow status,
  772. auto-follow access level, and permissions if they do not already exist in the database.
  773. It also updates the attributes of the existing Group objects if they have changed.
  774. """
  775. # Create new Organisation object
  776. def_org = get_or_create(db.session, Organisation, org_name="Default Org",
  777. org_description="Default Organisation")
  778. # Create new Administrator Group object
  779. try:
  780. gadm = get_or_create(db.session, Group, group_name='Administrators', group_description='Administrators',
  781. group_auto_follow=True, group_auto_follow_access_level=CaseAccessLevel.full_access.value,
  782. group_permissions=ac_get_mask_full_permissions())
  783. except exc.IntegrityError:
  784. db.session.rollback()
  785. log.warning('Administrator group integrity error. Group permissions were probably changed. Updating.')
  786. gadm = Group.query.filter(
  787. Group.group_name == 'Administrators'
  788. ).first()
  789. # Update Administrator Group object attributes
  790. if gadm.group_permissions != ac_get_mask_full_permissions():
  791. gadm.group_permissions = ac_get_mask_full_permissions()
  792. if gadm.group_auto_follow_access_level != CaseAccessLevel.full_access.value:
  793. gadm.group_auto_follow_access_level = CaseAccessLevel.full_access.value
  794. if gadm.group_auto_follow is not True:
  795. gadm.group_auto_follow = True
  796. db.session.commit()
  797. # Create new Analysts Group object
  798. try:
  799. ganalysts = get_or_create(db.session, Group, group_name='Analysts', group_description='Standard Analysts',
  800. group_auto_follow=False,
  801. group_auto_follow_access_level=CaseAccessLevel.full_access.value,
  802. group_permissions=ac_get_mask_analyst())
  803. except exc.IntegrityError:
  804. db.session.rollback()
  805. log.warning('Analysts group integrity error. Group permissions were probably changed. Updating.')
  806. ganalysts = get_group_by_name('Analysts')
  807. # Update Analysts Group object attributes
  808. if ganalysts.group_permissions != ac_get_mask_analyst():
  809. ganalysts.group_permissions = ac_get_mask_analyst()
  810. if ganalysts.group_auto_follow is not False:
  811. ganalysts.group_auto_follow = False
  812. if ganalysts.group_auto_follow_access_level != CaseAccessLevel.full_access.value:
  813. ganalysts.group_auto_follow_access_level = CaseAccessLevel.full_access.value
  814. db.session.commit()
  815. return def_org, gadm, ganalysts
  816. def create_safe_admin(def_org, gadm):
  817. """Creates a new admin user if one does not already exist.
  818. This function creates a new admin user with the specified username, email, and password
  819. if one does not already exist in the database. If an admin user already exists, it updates
  820. the email address of the existing user if it has changed.
  821. """
  822. # Get admin username and email from app config
  823. admin_username = app.config.get('IRIS_ADM_USERNAME')
  824. if admin_username is None:
  825. admin_username = 'administrator'
  826. admin_email = app.config.get('IRIS_ADM_EMAIL')
  827. if admin_email is None:
  828. admin_email = 'administrator@localhost'
  829. # Check if admin user already exists
  830. user = User.query.filter(or_(
  831. User.user == admin_username,
  832. User.email == admin_email
  833. )).first()
  834. password = None
  835. if not user:
  836. # Generate a new password if one was not provided in the app config
  837. password = app.config.get('IRIS_ADM_PASSWORD')
  838. if password is None:
  839. password = ''.join(random.choices(string.printable[:-6], k=16))
  840. log.info(f'Creating first admin user with username "{admin_username}"')
  841. # Create new User object for admin user
  842. user = User(
  843. user=admin_username,
  844. name=admin_username,
  845. email=admin_email,
  846. password=bc.generate_password_hash(password.encode('utf8')).decode('utf8'),
  847. active=True
  848. )
  849. # Generate a new API key if one was not provided in the app config
  850. api_key = app.config.get('IRIS_ADM_API_KEY')
  851. if api_key is None:
  852. api_key = secrets.token_urlsafe(nbytes=64)
  853. user.api_key = api_key
  854. db.session.add(user)
  855. db.session.commit()
  856. # Add admin user to admin group and default organisation
  857. add_user_to_group(user_id=user.id, group_id=gadm.group_id)
  858. add_user_to_organisation(user_id=user.id, org_id=def_org.org_id)
  859. log.warning(f">>> Administrator password: {password}")
  860. db.session.commit()
  861. else:
  862. if not os.environ.get('IRIS_ADM_PASSWORD'):
  863. # Prevent leak of user set password in logs
  864. log.warning(">>> Administrator already exists")
  865. if user.email != admin_email:
  866. # Update email address of existing admin user if it has changed
  867. log.warning(f'Email of administrator will be updated via config to {admin_email}')
  868. user.email = admin_email
  869. db.session.commit()
  870. return user, password
  871. def create_safe_case(user, client, groups):
  872. """Creates a new case if one does not already exist for the specified client.
  873. This function creates a new case with the specified name, description, SOC ID, user, and client
  874. if one does not already exist in the database for the specified client. It also adds the specified
  875. user and groups to the case with full access level.
  876. """
  877. # Check if a case already exists for the client
  878. case = Cases.query.filter(
  879. Cases.client_id == client.client_id
  880. ).first()
  881. if not case:
  882. # Create a new case for the client
  883. case = Cases(
  884. name="Initial Demo",
  885. description="This is a demonstration.",
  886. soc_id="soc_id_demo",
  887. user=user,
  888. client_id=client.client_id
  889. )
  890. # Validate the case and save it to the database
  891. case.validate_on_build()
  892. case.save()
  893. db.session.commit()
  894. # Add the specified user and groups to the case with full access level
  895. for group in groups:
  896. add_case_access_to_group(group=group,
  897. cases_list=[case.case_id],
  898. access_level=CaseAccessLevel.full_access.value)
  899. ac_add_user_effective_access(users_list=[user.id],
  900. case_id=1,
  901. access_level=CaseAccessLevel.full_access.value)
  902. return case
  903. def create_safe_report_types():
  904. """Creates new ReportType objects if they do not already exist.
  905. This function creates new ReportType objects with the specified names if they do not already
  906. exist in the database.
  907. """
  908. create_safe(db.session, ReportType, name="Investigation")
  909. create_safe(db.session, ReportType, name="Activities")
  910. def create_safe_attributes():
  911. """Creates new Attribute objects if they do not already exist.
  912. This function creates new Attribute objects with the specified display name, description,
  913. object type, and content if they do not already exist in the database.
  914. """
  915. create_safe_attr(db.session, attribute_display_name='IOC',
  916. attribute_description='Defines default attributes for IOCs', attribute_for='ioc',
  917. attribute_content={})
  918. create_safe_attr(db.session, attribute_display_name='Events',
  919. attribute_description='Defines default attributes for Events', attribute_for='event',
  920. attribute_content={})
  921. create_safe_attr(db.session, attribute_display_name='Assets',
  922. attribute_description='Defines default attributes for Assets', attribute_for='asset',
  923. attribute_content={})
  924. create_safe_attr(db.session, attribute_display_name='Tasks',
  925. attribute_description='Defines default attributes for Tasks', attribute_for='task',
  926. attribute_content={})
  927. create_safe_attr(db.session, attribute_display_name='Notes',
  928. attribute_description='Defines default attributes for Notes', attribute_for='note',
  929. attribute_content={})
  930. create_safe_attr(db.session, attribute_display_name='Evidences',
  931. attribute_description='Defines default attributes for Evidences', attribute_for='evidence',
  932. attribute_content={})
  933. create_safe_attr(db.session, attribute_display_name='Cases',
  934. attribute_description='Defines default attributes for Cases', attribute_for='case',
  935. attribute_content={})
  936. create_safe_attr(db.session, attribute_display_name='Customers',
  937. attribute_description='Defines default attributes for Customers', attribute_for='client',
  938. attribute_content={})
  939. def create_safe_ioctypes():
  940. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="AS",
  941. type_description="Autonomous system", type_taxonomy="")
  942. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="aba-rtn",
  943. type_description="ABA routing transit number",
  944. type_taxonomy="")
  945. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="account",
  946. type_description="Account of any type",
  947. type_taxonomy="")
  948. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="anonymised",
  949. type_description="Anonymised value - described with the anonymisation object via a relationship",
  950. type_taxonomy="")
  951. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="attachment",
  952. type_description="Attachment with external information",
  953. type_taxonomy="")
  954. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="authentihash",
  955. type_description="Authenticode executable signature hash", type_taxonomy="",
  956. type_validation_regex=r"[a-f0-9]{64}", type_validation_expect="64 hexadecimal characters"
  957. )
  958. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="boolean",
  959. type_description="Boolean value - to be used in objects",
  960. type_taxonomy="")
  961. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="btc",
  962. type_description="Bitcoin Address", type_taxonomy="")
  963. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="campaign-id",
  964. type_description="Associated campaign ID",
  965. type_taxonomy="")
  966. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="campaign-name",
  967. type_description="Associated campaign name",
  968. type_taxonomy="")
  969. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="cdhash",
  970. type_description="An Apple Code Directory Hash, identifying a code-signed Mach-O executable file",
  971. type_taxonomy="")
  972. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="chrome-extension-id",
  973. type_description="Chrome extension id",
  974. type_taxonomy="")
  975. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="community-id",
  976. type_description="a community ID flow hashing algorithm to map multiple traffic monitors into common flow id",
  977. type_taxonomy="")
  978. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="cookie",
  979. type_description="HTTP cookie as often stored on the user web client. This can include authentication cookie or session cookie.",
  980. type_taxonomy="")
  981. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="dash",
  982. type_description="Dash Address", type_taxonomy="")
  983. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="datetime",
  984. type_description="Datetime in the ISO 8601 format",
  985. type_taxonomy="")
  986. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="dkim",
  987. type_description="DKIM public key", type_taxonomy="")
  988. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="dkim-signature",
  989. type_description="DKIM signature", type_taxonomy="")
  990. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="dns-soa-email",
  991. type_description="RFC1035 mandates that DNS zones should have a SOA (Statement Of Authority) record that contains an email address where a PoC for the domain could be contacted. This can sometimes be used for attribution/linkage between different domains even if protected by whois privacy",
  992. type_taxonomy="")
  993. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="domain",
  994. type_description="A domain name used in the malware",
  995. type_taxonomy="")
  996. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="domain|ip",
  997. type_description="A domain name and its IP address (as found in DNS lookup) separated by a |",
  998. type_taxonomy="")
  999. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email",
  1000. type_description="An e-mail address", type_taxonomy="")
  1001. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-attachment",
  1002. type_description="File name of the email attachment.", type_taxonomy="")
  1003. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-body",
  1004. type_description="Email body", type_taxonomy="")
  1005. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-dst",
  1006. type_description="The destination email address. Used to describe the recipient when describing an e-mail.",
  1007. type_taxonomy="")
  1008. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-dst-display-name",
  1009. type_description="Email destination display name", type_taxonomy="")
  1010. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-header",
  1011. type_description="Email header", type_taxonomy="")
  1012. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-message-id",
  1013. type_description="The email message ID",
  1014. type_taxonomy="")
  1015. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-mime-boundary",
  1016. type_description="The email mime boundary separating parts in a multipart email",
  1017. type_taxonomy="")
  1018. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-reply-to",
  1019. type_description="Email reply to header",
  1020. type_taxonomy="")
  1021. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-src",
  1022. type_description="The source email address. Used to describe the sender when describing an e-mail.",
  1023. type_taxonomy="")
  1024. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-src-display-name",
  1025. type_description="Email source display name",
  1026. type_taxonomy="")
  1027. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-subject",
  1028. type_description="The subject of the email",
  1029. type_taxonomy="")
  1030. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-thread-index",
  1031. type_description="The email thread index header",
  1032. type_taxonomy="")
  1033. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="email-x-mailer",
  1034. type_description="Email x-mailer header",
  1035. type_taxonomy="")
  1036. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="favicon-mmh3",
  1037. type_description="favicon-mmh3 is the murmur3 hash of a favicon as used in Shodan.",
  1038. type_taxonomy="")
  1039. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename",
  1040. type_description="Filename", type_taxonomy="")
  1041. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename-pattern",
  1042. type_description="A pattern in the name of a file",
  1043. type_taxonomy="")
  1044. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|authentihash",
  1045. type_description="A checksum in md5 format",
  1046. type_taxonomy="",
  1047. type_validation_regex=r'.+\|[a-f0-9]{64}',
  1048. type_validation_expect="filename|64 hexadecimal characters")
  1049. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|impfuzzy",
  1050. type_description="Import fuzzy hash - a fuzzy hash created based on the imports in the sample.",
  1051. type_taxonomy="", )
  1052. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|imphash",
  1053. type_description="Import hash - a hash created based on the imports in the sample.",
  1054. type_taxonomy="",
  1055. type_validation_regex=r'.+\|[a-f0-9]{32}',
  1056. type_validation_expect="filename|32 hexadecimal characters")
  1057. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|md5",
  1058. type_description="A filename and an md5 hash separated by a |", type_taxonomy="",
  1059. type_validation_regex=r'.+\|[a-f0-9]{32}',
  1060. type_validation_expect="filename|32 hexadecimal characters")
  1061. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|pehash",
  1062. type_description="A filename and a PEhash separated by a |", type_taxonomy="",
  1063. type_validation_regex=r'.+\|[a-f0-9]{40}',
  1064. type_validation_expect="filename|40 hexadecimal characters")
  1065. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha1",
  1066. type_description="A filename and an sha1 hash separated by a |", type_taxonomy="",
  1067. type_validation_regex=r'.+\|[a-f0-9]{40}',
  1068. type_validation_expect="filename|40 hexadecimal characters")
  1069. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha224",
  1070. type_description="A filename and a sha-224 hash separated by a |", type_taxonomy="",
  1071. type_validation_regex=r'.+\|[a-f0-9]{56}',
  1072. type_validation_expect="filename|56 hexadecimal characters")
  1073. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha256",
  1074. type_description="A filename and an sha256 hash separated by a |", type_taxonomy="",
  1075. type_validation_regex=r'.+\|[a-f0-9]{64}',
  1076. type_validation_expect="filename|64 hexadecimal characters")
  1077. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha3-224",
  1078. type_description="A filename and an sha3-224 hash separated by a |", type_taxonomy="",
  1079. type_validation_regex=r'.+\|[a-f0-9]{56}',
  1080. type_validation_expect="filename|56 hexadecimal characters")
  1081. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha3-256",
  1082. type_description="A filename and an sha3-256 hash separated by a |", type_taxonomy="",
  1083. type_validation_regex=r'.+\|[a-f0-9]{64}',
  1084. type_validation_expect="filename|64 hexadecimal characters")
  1085. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha3-384",
  1086. type_description="A filename and an sha3-384 hash separated by a |", type_taxonomy="",
  1087. type_validation_regex=r'.+\|[a-f0-9]{96}',
  1088. type_validation_expect="filename|96 hexadecimal characters")
  1089. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha3-512",
  1090. type_description="A filename and an sha3-512 hash separated by a |", type_taxonomy="",
  1091. type_validation_regex=r'.+\|[a-f0-9]{128}',
  1092. type_validation_expect="filename|128 hexadecimal characters")
  1093. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha384",
  1094. type_description="A filename and a sha-384 hash separated by a |", type_taxonomy="",
  1095. type_validation_regex=r'.+\|[a-f0-9]{96}',
  1096. type_validation_expect="filename|96 hexadecimal characters")
  1097. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha512",
  1098. type_description="A filename and a sha-512 hash separated by a |", type_taxonomy="",
  1099. type_validation_regex=r'.+\|[a-f0-9]{128}',
  1100. type_validation_expect="filename|128 hexadecimal characters")
  1101. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha512/224",
  1102. type_description="A filename and a sha-512/224 hash separated by a |", type_taxonomy="",
  1103. type_validation_regex=r'.+\|[a-f0-9]{56}',
  1104. type_validation_expect="filename|56 hexadecimal characters")
  1105. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|sha512/256",
  1106. type_description="A filename and a sha-512/256 hash separated by a |", type_taxonomy="",
  1107. type_validation_regex=r'.+\|[a-f0-9]{64}',
  1108. type_validation_expect="filename|64 hexadecimal characters")
  1109. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|ssdeep",
  1110. type_description="A checksum in ssdeep format",
  1111. type_taxonomy="")
  1112. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|tlsh",
  1113. type_description="A filename and a Trend Micro Locality Sensitive Hash separated by a |",
  1114. type_taxonomy="",
  1115. type_validation_regex=r'.+\|t?[a-f0-9]{35,}',
  1116. type_validation_expect="filename|at least 35 hexadecimal characters, optionally starting with t1 instead of hexadecimal characters"
  1117. )
  1118. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="filename|vhash",
  1119. type_description="A filename and a VirusTotal hash separated by a |", type_taxonomy="")
  1120. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="first-name",
  1121. type_description="First name of a natural person",
  1122. type_taxonomy="")
  1123. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="float",
  1124. type_description="A floating point value.", type_taxonomy="")
  1125. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="full-name",
  1126. type_description="Full name of a natural person",
  1127. type_taxonomy="")
  1128. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="gene",
  1129. type_description="GENE - Go Evtx sigNature Engine",
  1130. type_taxonomy="")
  1131. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="git-commit-id",
  1132. type_description="A git commit ID.", type_taxonomy="",
  1133. type_validation_regex=r"[a-f0-9]{40}", type_validation_expect="40 hexadecimal characters")
  1134. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="github-organisation",
  1135. type_description="A github organisation",
  1136. type_taxonomy="")
  1137. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="github-repository",
  1138. type_description="A github repository",
  1139. type_taxonomy="")
  1140. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="github-username",
  1141. type_description="A github user name",
  1142. type_taxonomy="")
  1143. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="hassh-md5",
  1144. type_description="hassh is a network fingerprinting standard which can be used to identify specific Client SSH implementations. The fingerprints can be easily stored, searched and shared in the form of an MD5 fingerprint.",
  1145. type_taxonomy="",
  1146. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1147. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="hasshserver-md5",
  1148. type_description="hasshServer is a network fingerprinting standard which can be used to identify specific Server SSH implementations. The fingerprints can be easily stored, searched and shared in the form of an MD5 fingerprint.",
  1149. type_taxonomy="",
  1150. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1151. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="hex",
  1152. type_description="A value in hexadecimal format",
  1153. type_taxonomy="")
  1154. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="hostname",
  1155. type_description="A full host/dnsname of an attacker",
  1156. type_taxonomy="")
  1157. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="hostname|port",
  1158. type_description="Hostname and port number separated by a |", type_taxonomy="")
  1159. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="http-method",
  1160. type_description="HTTP method used by the malware (e.g. POST, GET, …).", type_taxonomy="")
  1161. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="iban",
  1162. type_description="International Bank Account Number",
  1163. type_taxonomy="")
  1164. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="identity-card-number",
  1165. type_description="Identity card number",
  1166. type_taxonomy="")
  1167. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="impfuzzy",
  1168. type_description="A fuzzy hash of import table of Portable Executable format", type_taxonomy="")
  1169. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="imphash",
  1170. type_description="Import hash - a hash created based on the imports in the sample.",
  1171. type_taxonomy="",
  1172. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1173. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ip-any",
  1174. type_description="A source or destination IP address of the attacker or C&C server",
  1175. type_taxonomy="")
  1176. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ip-dst",
  1177. type_description="A destination IP address of the attacker or C&C server", type_taxonomy="")
  1178. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ip-dst|port",
  1179. type_description="IP destination and port number separated by a |", type_taxonomy="")
  1180. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ip-src",
  1181. type_description="A source IP address of the attacker",
  1182. type_taxonomy="")
  1183. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ip-src|port",
  1184. type_description="IP source and port number separated by a |", type_taxonomy="")
  1185. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ja3-fingerprint-md5",
  1186. type_description="JA3 is a method for creating SSL/TLS client fingerprints that should be easy to produce on any platform and can be easily shared for threat intelligence.",
  1187. type_taxonomy="",
  1188. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1189. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="jabber-id",
  1190. type_description="Jabber ID", type_taxonomy="")
  1191. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="jarm-fingerprint",
  1192. type_description="JARM is a method for creating SSL/TLS server fingerprints.", type_taxonomy="",
  1193. type_validation_regex=r"[a-f0-9]{62}", type_validation_expect="62 hexadecimal characters")
  1194. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="kusto-query",
  1195. type_description="Kusto query - Kusto from Microsoft Azure is a service for storing and running interactive analytics over Big Data.",
  1196. type_taxonomy="")
  1197. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="link",
  1198. type_description="Link to an external information",
  1199. type_taxonomy="")
  1200. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="mac-address",
  1201. type_description="Mac address", type_taxonomy="")
  1202. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="mac-eui-64",
  1203. type_description="Mac EUI-64 address", type_taxonomy="")
  1204. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="malware-sample",
  1205. type_description="Attachment containing encrypted malware sample", type_taxonomy="")
  1206. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="malware-type",
  1207. type_description="Malware type", type_taxonomy="")
  1208. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="md5",
  1209. type_description="A checksum in md5 format", type_taxonomy="",
  1210. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1211. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="middle-name",
  1212. type_description="Middle name of a natural person",
  1213. type_taxonomy="")
  1214. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="mime-type",
  1215. type_description="A media type (also MIME type and content type) is a two-part identifier for file formats and format contents transmitted on the Internet",
  1216. type_taxonomy="")
  1217. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="mobile-application-id",
  1218. type_description="The application id of a mobile application", type_taxonomy="")
  1219. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="mutex",
  1220. type_description="Mutex, use the format \\BaseNamedObjects<Mutex>", type_taxonomy="")
  1221. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="named pipe",
  1222. type_description="Named pipe, use the format .\\pipe<PipeName>", type_taxonomy="")
  1223. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="other",
  1224. type_description="Other attribute", type_taxonomy="")
  1225. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="file-path",
  1226. type_description="Path of file", type_taxonomy="")
  1227. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pattern-in-file",
  1228. type_description="Pattern in file that identifies the malware", type_taxonomy="")
  1229. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pattern-in-memory",
  1230. type_description="Pattern in memory dump that identifies the malware", type_taxonomy="")
  1231. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pattern-in-traffic",
  1232. type_description="Pattern in network traffic that identifies the malware", type_taxonomy="")
  1233. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pdb",
  1234. type_description="Microsoft Program database (PDB) path information", type_taxonomy="")
  1235. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pehash",
  1236. type_description="PEhash - a hash calculated based of certain pieces of a PE executable file",
  1237. type_taxonomy="",
  1238. type_validation_regex=r"[a-f0-9]{40}", type_validation_expect="40 hexadecimal characters")
  1239. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pgp-private-key",
  1240. type_description="A PGP private key",
  1241. type_taxonomy="")
  1242. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="pgp-public-key",
  1243. type_description="A PGP public key", type_taxonomy="")
  1244. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="phone-number",
  1245. type_description="Telephone Number", type_taxonomy="")
  1246. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="port",
  1247. type_description="Port number", type_taxonomy="")
  1248. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="process-state",
  1249. type_description="State of a process", type_taxonomy="")
  1250. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="prtn",
  1251. type_description="Premium-Rate Telephone Number",
  1252. type_taxonomy="")
  1253. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="regkey",
  1254. type_description="Registry key or value", type_taxonomy="")
  1255. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="regkey|value",
  1256. type_description="Registry value + data separated by |",
  1257. type_taxonomy="")
  1258. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha1",
  1259. type_description="A checksum in sha1 format", type_taxonomy="",
  1260. type_validation_regex=r"[a-f0-9]{40}", type_validation_expect="40 hexadecimal characters")
  1261. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha224",
  1262. type_description="A checksum in sha-224 format",
  1263. type_taxonomy="",
  1264. type_validation_regex=r"[a-f0-9]{56}", type_validation_expect="56 hexadecimal characters")
  1265. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha256",
  1266. type_description="A checksum in sha256 format",
  1267. type_taxonomy="",
  1268. type_validation_regex=r"[a-f0-9]{64}", type_validation_expect="64 hexadecimal characters")
  1269. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha3-224",
  1270. type_description="A checksum in sha3-224 format",
  1271. type_taxonomy="",
  1272. type_validation_regex=r"[a-f0-9]{56}", type_validation_expect="56 hexadecimal characters")
  1273. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha3-256",
  1274. type_description="A checksum in sha3-256 format",
  1275. type_taxonomy="",
  1276. type_validation_regex=r"[a-f0-9]{64}", type_validation_expect="64 hexadecimal characters")
  1277. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha3-384",
  1278. type_description="A checksum in sha3-384 format",
  1279. type_taxonomy="",
  1280. type_validation_regex=r"[a-f0-9]{96}", type_validation_expect="96 hexadecimal characters")
  1281. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha3-512",
  1282. type_description="A checksum in sha3-512 format",
  1283. type_taxonomy="",
  1284. type_validation_regex=r"[a-f0-9]{128}", type_validation_expect="128 hexadecimal characters")
  1285. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha384",
  1286. type_description="A checksum in sha-384 format",
  1287. type_taxonomy="",
  1288. type_validation_regex=r"[a-f0-9]{96}", type_validation_expect="96 hexadecimal characters")
  1289. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha512",
  1290. type_description="A checksum in sha-512 format",
  1291. type_taxonomy="",
  1292. type_validation_regex=r"[a-f0-9]{128}", type_validation_expect="128 hexadecimal characters")
  1293. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha512/224",
  1294. type_description="A checksum in the sha-512/224 format",
  1295. type_taxonomy="",
  1296. type_validation_regex=r"[a-f0-9]{56}", type_validation_expect="56 hexadecimal characters")
  1297. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sha512/256",
  1298. type_description="A checksum in the sha-512/256 format",
  1299. type_taxonomy="",
  1300. type_validation_regex=r"[a-f0-9]{64}", type_validation_expect="64 hexadecimal characters")
  1301. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="sigma",
  1302. type_description="Sigma - Generic Signature Format for SIEM Systems", type_taxonomy="")
  1303. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="size-in-bytes",
  1304. type_description="Size expressed in bytes",
  1305. type_taxonomy="")
  1306. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="snort",
  1307. type_description="An IDS rule in Snort rule-format",
  1308. type_taxonomy="")
  1309. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ssdeep",
  1310. type_description="A checksum in ssdeep format",
  1311. type_taxonomy="")
  1312. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="ssh-fingerprint",
  1313. type_description="A fingerprint of SSH key material",
  1314. type_taxonomy="")
  1315. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="stix2-pattern",
  1316. type_description="STIX 2 pattern", type_taxonomy="")
  1317. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-email",
  1318. type_description="Attack Targets Email(s)",
  1319. type_taxonomy="")
  1320. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-external",
  1321. type_description="External Target Organizations Affected by this Attack", type_taxonomy="")
  1322. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-location",
  1323. type_description="Attack Targets Physical Location(s)", type_taxonomy="")
  1324. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-machine",
  1325. type_description="Attack Targets Machine Name(s)",
  1326. type_taxonomy="")
  1327. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-org",
  1328. type_description="Attack Targets Department or Organization(s)", type_taxonomy="")
  1329. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="target-user",
  1330. type_description="Attack Targets Username(s)",
  1331. type_taxonomy="")
  1332. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="telfhash",
  1333. type_description="telfhash is symbol hash for ELF files, just like imphash is imports hash for PE files.",
  1334. type_taxonomy="",
  1335. type_validation_regex=r"[a-f0-9]{70}", type_validation_expect="70 hexadecimal characters")
  1336. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="text",
  1337. type_description="Name, ID or a reference", type_taxonomy="")
  1338. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="threat-actor",
  1339. type_description="A string identifying the threat actor",
  1340. type_taxonomy="")
  1341. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="tlsh",
  1342. type_description="A checksum in the Trend Micro Locality Sensitive Hash format",
  1343. type_taxonomy="",
  1344. type_validation_regex=r"^t?[a-f0-9]{35,}",
  1345. type_validation_expect="at least 35 hexadecimal characters, optionally starting with t1 instead of hexadecimal characters")
  1346. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="travel-details",
  1347. type_description="Travel details", type_taxonomy="")
  1348. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="twitter-id",
  1349. type_description="Twitter ID", type_taxonomy="")
  1350. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="uri",
  1351. type_description="Uniform Resource Identifier", type_taxonomy="")
  1352. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="url", type_description="url",
  1353. type_taxonomy="")
  1354. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="user-agent",
  1355. type_description="The user-agent used by the malware in the HTTP request.", type_taxonomy="")
  1356. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="vhash",
  1357. type_description="A VirusTotal checksum", type_taxonomy="")
  1358. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="vulnerability",
  1359. type_description="A reference to the vulnerability used in the exploit", type_taxonomy="")
  1360. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="weakness",
  1361. type_description="A reference to the weakness used in the exploit", type_taxonomy="")
  1362. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-creation-date",
  1363. type_description="The date of domain’s creation, obtained from the WHOIS information.",
  1364. type_taxonomy="")
  1365. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-registrant-email",
  1366. type_description="The e-mail of a domain’s registrant, obtained from the WHOIS information.",
  1367. type_taxonomy="")
  1368. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-registrant-name",
  1369. type_description="The name of a domain’s registrant, obtained from the WHOIS information.",
  1370. type_taxonomy="")
  1371. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-registrant-org",
  1372. type_description="The org of a domain’s registrant, obtained from the WHOIS information.",
  1373. type_taxonomy="")
  1374. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-registrant-phone",
  1375. type_description="The phone number of a domain’s registrant, obtained from the WHOIS information.",
  1376. type_taxonomy="")
  1377. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="whois-registrar",
  1378. type_description="The registrar of the domain, obtained from the WHOIS information.",
  1379. type_taxonomy="")
  1380. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="windows-scheduled-task",
  1381. type_description="A scheduled task in windows",
  1382. type_taxonomy="")
  1383. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="windows-service-displayname",
  1384. type_description="A windows service’s displayname, not to be confused with the windows-service-name. This is the name that applications will generally display as the service’s name in applications.",
  1385. type_taxonomy="")
  1386. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="windows-service-name",
  1387. type_description="A windows service name. This is the name used internally by windows. Not to be confused with the windows-service-displayname.",
  1388. type_taxonomy="")
  1389. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="x509-fingerprint-md5",
  1390. type_description="X509 fingerprint in MD5 format", type_taxonomy="",
  1391. type_validation_regex=r"[a-f0-9]{32}", type_validation_expect="32 hexadecimal characters")
  1392. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="x509-fingerprint-sha1",
  1393. type_description="X509 fingerprint in SHA-1 format", type_taxonomy="",
  1394. type_validation_regex=r"[a-f0-9]{40}", type_validation_expect="40 hexadecimal characters")
  1395. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="x509-fingerprint-sha256",
  1396. type_description="X509 fingerprint in SHA-256 format", type_taxonomy="",
  1397. type_validation_regex=r"[a-f0-9]{64}", type_validation_expect="64 hexadecimal characters")
  1398. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="xmr",
  1399. type_description="Monero Address", type_taxonomy="")
  1400. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="yara",
  1401. type_description="Yara signature", type_taxonomy="")
  1402. create_safe_limited(db.session, IocType, ["type_name", "type_description"], type_name="zeek",
  1403. type_description="An NIDS rule in the Zeek rule-format",
  1404. type_taxonomy="")
  1405. def create_safe_os_types():
  1406. create_safe(db.session, OsType, type_name="Windows")
  1407. create_safe(db.session, OsType, type_name="Linux")
  1408. create_safe(db.session, OsType, type_name="AIX")
  1409. create_safe(db.session, OsType, type_name="MacOS")
  1410. create_safe(db.session, OsType, type_name="Apple iOS")
  1411. create_safe(db.session, OsType, type_name="Cisco iOS")
  1412. create_safe(db.session, OsType, type_name="Android")
  1413. def create_safe_tlp():
  1414. create_safe(db.session, Tlp, tlp_name="red", tlp_bscolor="danger")
  1415. create_safe(db.session, Tlp, tlp_name="amber", tlp_bscolor="warning")
  1416. create_safe(db.session, Tlp, tlp_name="green", tlp_bscolor="success")
  1417. create_safe(db.session, Tlp, tlp_name="clear", tlp_bscolor="black")
  1418. create_safe(db.session, Tlp, tlp_name="amber+strict", tlp_bscolor="warning")
  1419. def create_safe_server_settings():
  1420. if not ServerSettings.query.count():
  1421. create_safe(db.session, ServerSettings,
  1422. http_proxy="", https_proxy="", prevent_post_mod_repush=False,
  1423. prevent_post_objects_repush=False,
  1424. password_policy_min_length="12", password_policy_upper_case=True,
  1425. password_policy_lower_case=True, password_policy_digit=True,
  1426. password_policy_special_chars="", enforce_mfa=app.config.get("MFA_ENABLED", False))
  1427. def register_modules_pipelines():
  1428. modules = IrisModule.query.with_entities(
  1429. IrisModule.module_name,
  1430. IrisModule.module_config
  1431. ).filter(
  1432. IrisModule.has_pipeline == True
  1433. ).all()
  1434. for module in modules:
  1435. module = module[0]
  1436. inst, _ = instantiate_module_from_name(module)
  1437. if not inst:
  1438. continue
  1439. inst.internal_configure(celery_decorator=celery.task,
  1440. evidence_storage=None,
  1441. mod_web_config=module[1])
  1442. status = inst.get_tasks_for_registration()
  1443. if status.is_failure():
  1444. log.warning("Failed getting tasks for module {}".format(module))
  1445. continue
  1446. tasks = status.get_data()
  1447. for task in tasks:
  1448. celery.register_task(task)
  1449. def register_default_modules():
  1450. modules = ['iris_vt_module', 'iris_misp_module', 'iris_check_module',
  1451. 'iris_webhooks_module', 'iris_intelowl_module']
  1452. for module_name in modules:
  1453. class_, _ = instantiate_module_from_name(module_name)
  1454. is_ready, logs = check_module_health(class_)
  1455. if not is_ready:
  1456. log.info("Attempted to initiate {mod}. Got {err}".format(mod=module_name, err=",".join(logs)))
  1457. return False
  1458. module, logs = register_module(module_name)
  1459. if module is None:
  1460. log.info("Attempted to add {mod}. Got {err}".format(mod=module_name, err=logs))
  1461. else:
  1462. iris_module_disable_by_id(module.id)
  1463. log.info('Successfully registered {mod}'.format(mod=module_name))
  1464. def custom_assets_symlinks():
  1465. try:
  1466. source_paths = glob.glob(os.path.join(app.config['ASSET_STORE_PATH'], "*"))
  1467. for store_fullpath in source_paths:
  1468. filename = store_fullpath.split(os.path.sep)[-1]
  1469. show_fullpath = os.path.join(app.config['APP_PATH'], 'app',
  1470. app.config['ASSET_SHOW_PATH'].strip(os.path.sep), filename)
  1471. if not os.path.islink(show_fullpath):
  1472. os.symlink(store_fullpath, show_fullpath)
  1473. log.info(f"Created assets img symlink {store_fullpath} -> {show_fullpath}")
  1474. except Exception as e:
  1475. log.error(f"Error: {e}")
  1476. def create_directories():
  1477. log.info("Attempting to create data directories")
  1478. for d in ['UPLOADED_PATH', 'TEMPLATES_PATH', 'BACKUP_PATH', 'ASSET_STORE_PATH', 'DATASTORE_PATH']:
  1479. try:
  1480. log.info(f'Creating directory {d}')
  1481. os.makedirs(app.config.get(d), exist_ok=True)
  1482. except OSError as e:
  1483. log.error(f"Failed to create directory {app.config.get(d)}: {e}")