diff options
Diffstat (limited to 'day9')
| -rw-r--r-- | day9/task5_vue/backend/__init__.py | 0 | ||||
| -rw-r--r-- | day9/task5_vue/backend/core/__init__.py | 0 | ||||
| -rw-r--r-- | day9/task5_vue/backend/database/__init__.py | 0 | ||||
| -rw-r--r-- | day9/task5_vue/backend/database/field_types.py | 20 | ||||
| -rw-r--r-- | day9/task5_vue/backend/database/validators.py | 16 | ||||
| -rw-r--r-- | day9/task5_vue/package-lock.json | 443 | ||||
| -rw-r--r-- | day9/task5_vue/package.json | 2 | ||||
| -rw-r--r-- | day9/task5_vue/src/App.vue | 62 | ||||
| -rw-r--r-- | day9/task5_vue/src/components/EditFormBox.vue | 6 | ||||
| -rw-r--r-- | day9/task5_vue/src/components/PopupMessage.vue | 28 | ||||
| -rw-r--r-- | day9/task5_vue/src/components/Table.vue | 48 | ||||
| -rw-r--r-- | day9/task5_vue/tests/__init__.py | 0 | ||||
| -rw-r--r-- | day9/task5_vue/tests/test_db_validators.py | 124 | ||||
| -rw-r--r-- | day9/task5_vue/webpack.config.js | 8 |
14 files changed, 702 insertions, 55 deletions
diff --git a/day9/task5_vue/backend/__init__.py b/day9/task5_vue/backend/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/day9/task5_vue/backend/__init__.py diff --git a/day9/task5_vue/backend/core/__init__.py b/day9/task5_vue/backend/core/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/day9/task5_vue/backend/core/__init__.py diff --git a/day9/task5_vue/backend/database/__init__.py b/day9/task5_vue/backend/database/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/day9/task5_vue/backend/database/__init__.py diff --git a/day9/task5_vue/backend/database/field_types.py b/day9/task5_vue/backend/database/field_types.py index d0b2c3b..8713882 100644 --- a/day9/task5_vue/backend/database/field_types.py +++ b/day9/task5_vue/backend/database/field_types.py @@ -12,7 +12,7 @@ class Field(ABC): @property @abstractmethod - def sql_line(self): + def sql_line(self) -> str: pass def validate(self, value): @@ -21,7 +21,7 @@ class Field(ABC): class TextField(Field): - def __init__(self, max_length, is_variable_length, nullable, default, validators=None): + def __init__(self, max_length, is_variable_length, nullable, default=None, validators=None): super().__init__(validators) self.max_length = max_length @@ -45,7 +45,7 @@ class TextField(Field): class IntegerField(Field): - def __init__(self, max_length, nullable, is_auto_increment, default, validators=None): + def __init__(self, max_length, nullable, is_auto_increment, default=None, validators=None): super().__init__(validators) self.max_length = max_length @@ -62,7 +62,7 @@ class IntegerField(Field): 'NULL' if self.nullable else 'NOT NULL' ] - if self.default is not None: + if self.default is not None or self.nullable: request.append(f'DEFAULT "{self.default}"') if self.is_auto_increment: @@ -72,7 +72,7 @@ class IntegerField(Field): class DateField(Field): - def __init__(self, nullable, default, validators=None): + def __init__(self, nullable, default=None, validators=None): super().__init__(validators) self.nullable = nullable @@ -84,14 +84,14 @@ class DateField(Field): def sql_line(self): request = ['date', 'NULL' if self.nullable else 'NOT NULL'] - if self.default is not None: + if self.default is not None or self.nullable: request.append(f'DEFAULT "{self.default}"') return ' '.join(request) class TimeField(Field): - def __init__(self, nullable, default, validators=None): + def __init__(self, nullable, default=None, validators=None): super().__init__(validators) self.nullable = nullable @@ -103,14 +103,14 @@ class TimeField(Field): def sql_line(self): request = ['time', 'NULL' if self.nullable else 'NOT NULL'] - if self.default is not None: + if self.default is not None or self.nullable: request.append(f'DEFAULT "{self.default}"') return ' '.join(request) class DatetimeField(Field): - def __init__(self, nullable, default, validators=None): + def __init__(self, nullable, default=None, validators=None): super().__init__(validators) self.nullable = nullable @@ -122,7 +122,7 @@ class DatetimeField(Field): def sql_line(self): request = ['datetime', 'NULL' if self.nullable else 'NOT NULL'] - if self.default is not None: + if self.default is not None or self.nullable: request.append(f'DEFAULT "{self.default}"') return ' '.join(request) diff --git a/day9/task5_vue/backend/database/validators.py b/day9/task5_vue/backend/database/validators.py index e4b7310..112af2b 100644 --- a/day9/task5_vue/backend/database/validators.py +++ b/day9/task5_vue/backend/database/validators.py @@ -32,8 +32,12 @@ class ValidateType(Validator): class ValidateLength(Validator): @staticmethod def validate(value, field_object): + if hasattr(field_object, 'is_variable_length') and not field_object.is_variable_length: + if len(str(value)) < field_object.max_length: + raise ValidationError('Value has too few characters') + if len(str(value)) > field_object.max_length: - raise ValidationError('Value has too many digits') + raise ValidationError('Value has too many characters') class ValidateTime(Validator): @@ -65,14 +69,14 @@ class ValidateDate(Validator): if year < 0: raise ValidationError('Wrong year value') - if month not in range(1, 12): + if month not in range(1, 12 + 1): raise ValidationError('Wrong month value') if month == 2: if year % 4 == 0 and year % 100 != 0 or year % 400 == 0: - febr_range = range(1, 29) + febr_range = range(1, 29 + 1) else: - febr_range = range(1, 28) + febr_range = range(1, 28 + 1) if day not in febr_range: raise ValidationError('Wrong day value') else: @@ -81,7 +85,7 @@ class ValidateDate(Validator): 6: 30, 7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31 }.get(month) - if day not in range(1, days_count): + if day not in range(1, days_count + 1): raise ValidationError('Wrong day value') @@ -93,4 +97,4 @@ class ValidateDatetime(Validator): raise ValidationError('Wrong datetime format') else: ValidateDate.validate(datetime[0], {}) - ValidateTime.validate(datetime[1], {})
\ No newline at end of file + ValidateTime.validate(datetime[1], {}) diff --git a/day9/task5_vue/package-lock.json b/day9/task5_vue/package-lock.json index 7718c3d..2fdde82 100644 --- a/day9/task5_vue/package-lock.json +++ b/day9/task5_vue/package-lock.json @@ -463,6 +463,23 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -497,6 +514,13 @@ } } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -507,11 +531,32 @@ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true, + "optional": true + }, "axios": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", @@ -606,6 +651,16 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -800,6 +855,13 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -893,6 +955,12 @@ "wrap-ansi": "^5.1.0" } }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -915,6 +983,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "optional": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", @@ -1113,6 +1191,16 @@ "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -1180,6 +1268,13 @@ } } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "optional": true + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -1221,6 +1316,17 @@ "stream-shift": "^1.0.0" } }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, "elliptic": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", @@ -1374,6 +1480,13 @@ "homedir-polyfill": "^1.0.1" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "optional": true + }, "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", @@ -1452,6 +1565,13 @@ } } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "optional": true + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -1550,6 +1670,25 @@ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -2084,6 +2223,16 @@ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", @@ -2161,6 +2310,24 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "optional": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -2244,6 +2411,18 @@ "parse-passwd": "^1.0.0" } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", @@ -2268,6 +2447,13 @@ "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, "import-local": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", @@ -2443,6 +2629,13 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -2469,11 +2662,25 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true, + "optional": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2484,11 +2691,25 @@ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -2497,6 +2718,19 @@ "minimist": "^1.2.0" } }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -2511,6 +2745,43 @@ "invert-kv": "^2.0.0" } }, + "less": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", + "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.0", + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + } + }, "loader-runner": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", @@ -2660,6 +2931,30 @@ "brorand": "^1.0.1" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true, + "optional": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "optional": true, + "requires": { + "mime-db": "1.40.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -2844,6 +3139,13 @@ "path-key": "^2.0.0" } }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "optional": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3038,6 +3340,13 @@ "sha.js": "^2.4.8" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -3187,6 +3496,16 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -3203,6 +3522,13 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==", + "dev": true, + "optional": true + }, "public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -3251,6 +3577,13 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "optional": true + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -3326,6 +3659,35 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3432,6 +3794,13 @@ "ret": "~0.1.10" } }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -3662,6 +4031,24 @@ "extend-shallow": "^3.0.0" } }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, "ssri": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", @@ -3878,6 +4265,26 @@ "repeat-string": "^1.6.1" } }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "optional": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + } + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -3893,6 +4300,23 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -4026,12 +4450,31 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true, + "optional": true + }, "v8-compile-cache": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", "dev": true }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "vm-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", diff --git a/day9/task5_vue/package.json b/day9/task5_vue/package.json index 650d57a..d439908 100644 --- a/day9/task5_vue/package.json +++ b/day9/task5_vue/package.json @@ -19,6 +19,8 @@ "babel": "^6.23.0", "babel-loader": "^8.0.6", "css-loader": "^3.1.0", + "less": "^3.9.0", + "less-loader": "^5.0.0", "vue-loader": "^15.7.1", "vue-template-compiler": "^2.6.10", "webpack-cli": "^3.3.6" diff --git a/day9/task5_vue/src/App.vue b/day9/task5_vue/src/App.vue index 2af8b20..8def105 100644 --- a/day9/task5_vue/src/App.vue +++ b/day9/task5_vue/src/App.vue @@ -2,13 +2,18 @@ <div> <EditFormBox v-bind:form-type="formType" - v-bind:cancel-callback="hideForm" v-bind:table-row="formData" + v-bind:cancel-callback="hideForm" + v-bind:show-popup="showPopup" v-if="isFormShown" /> <Table v-bind:table-data="tableData" v-bind:show-form-callback="showForm"/> <UploadFileButton v-if="!isFormShown"/> <AddNewEntryButton v-if="!isFormShown" v-bind:show-form-callback="showForm"/> + + <transition name="fade"> + <PopupMessage v-if="isPopupShown" v-bind:message="popupMessage"/> + </transition> </div> </template> @@ -17,35 +22,57 @@ import Table from "./components/Table.vue"; import UploadFileButton from "./components/UploadFileButton.vue"; import AddNewEntryButton from './components/AddNewEntryButton.vue'; + import PopupMessage from './components/PopupMessage.vue' + import axios from 'axios'; + export default { name: "App", - components: {EditFormBox, Table, UploadFileButton, AddNewEntryButton}, + components: {PopupMessage, EditFormBox, Table, UploadFileButton, AddNewEntryButton}, data() { return { tableData: [], formType: null, formData: null, - isFormShown: false + isFormShown: false, + + isPopupShown: false, + popupMessage: '', } }, mounted() { - axios - .request({ - url: '/api/get/', - method: 'post', - headers: {'Content-Type': 'application/json'}, - data: JSON.stringify({'type': 'full'}) - }) - .then(response => { - this.tableData = response.data; - }) + this.updateTable(); }, methods: { + updateTable() { + axios + .request({ + url: '/api/get/', + method: 'post', + headers: {'Content-Type': 'application/json'}, + data: JSON.stringify({'type': 'full'}) + }) + .then(response => { + this.tableData = response.data; + }) + }, + + showPopup(message) { + if (!this.isPopupShown) { + this.isPopupShown = true; + this.popupMessage = message; + + setTimeout(() => { + this.isPopupShown = false; + this.popupMessage = ''; + }, 2000) + } + }, + showForm(formType, formData) { this.formType = formType; this.formData = formData; @@ -56,11 +83,18 @@ this.formType = null; this.formData = null; this.isFormShown = false; + + this.updateTable() } } } </script> <style scoped> - + .fade-enter-active, .fade-leave-active { + transition: opacity .5s; + } + .fade-enter, .fade-leave-to { + opacity: 0; + } </style>
\ No newline at end of file diff --git a/day9/task5_vue/src/components/EditFormBox.vue b/day9/task5_vue/src/components/EditFormBox.vue index 861a82d..c994656 100644 --- a/day9/task5_vue/src/components/EditFormBox.vue +++ b/day9/task5_vue/src/components/EditFormBox.vue @@ -111,7 +111,7 @@ export default { name: "EditFormBox", - props: ['formType', 'cancelCallback', 'tableRow'], + props: ['formType', 'cancelCallback', 'tableRow', 'showPopup'], data() { return { @@ -178,6 +178,10 @@ headers: {'Content-Type': 'application/json'}, data: JSON.stringify(formData) }) + .then(response => { + this.cancelCallback(); + this.showPopup('Database updated successfully'); + }); } } } diff --git a/day9/task5_vue/src/components/PopupMessage.vue b/day9/task5_vue/src/components/PopupMessage.vue new file mode 100644 index 0000000..a905b4d --- /dev/null +++ b/day9/task5_vue/src/components/PopupMessage.vue @@ -0,0 +1,28 @@ +<template> + <div ref="container" class="popupContainer"> + {{ message }} + </div> +</template> + +<script> + export default { + name: "PopupMessage", + props: ['message'], + } +</script> + +<style scoped> + .popupContainer { + background-color: #00ff5e; + padding: 30px; + + font-size: 30px; + text-align: center; + + position: fixed; + bottom: 0; + + left: 0; + right: 0; + } +</style>
\ No newline at end of file diff --git a/day9/task5_vue/src/components/Table.vue b/day9/task5_vue/src/components/Table.vue index d9296d9..a186277 100644 --- a/day9/task5_vue/src/components/Table.vue +++ b/day9/task5_vue/src/components/Table.vue @@ -1,29 +1,29 @@ <template> <table> - <thead> - <tr> - <th v-for="header in tableData.headers"> - {{ header }} - </th> - <th></th> - <th></th> - </tr> - </thead> - <tbody> - <tr v-for="(row) in tableData.content"> - <td>{{ row[0] }}</td> - <td v-for="(column) in row.slice(1)"> - {{ column }} - </td> - <td> - <button @click="showEditForm(`${row[0]}`)">✎</button> - </td> - <td> - <button @click="removeField(`${row[0]}`)">✖</button> - </td> - </tr> - </tbody> - </table> + <thead> + <tr> + <th v-for="header in tableData.headers"> + {{ header }} + </th> + <th></th> + <th></th> + </tr> + </thead> + <tbody> + <tr v-for="(row) in tableData.content"> + <td>{{ row[0] }}</td> + <td v-for="(column) in row.slice(1)"> + {{ column }} + </td> + <td> + <button @click="showEditForm(`${row[0]}`)">✎</button> + </td> + <td> + <button @click="removeField(`${row[0]}`)">✖</button> + </td> + </tr> + </tbody> + </table> </template> <script> diff --git a/day9/task5_vue/tests/__init__.py b/day9/task5_vue/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/day9/task5_vue/tests/__init__.py diff --git a/day9/task5_vue/tests/test_db_validators.py b/day9/task5_vue/tests/test_db_validators.py new file mode 100644 index 0000000..b83fcf1 --- /dev/null +++ b/day9/task5_vue/tests/test_db_validators.py @@ -0,0 +1,124 @@ +from backend.database.validators import ( + ValidateNull, ValidateType, ValidateTime, + ValidateDatetime, ValidateDate, ValidateLength, + ValidationError +) +from backend.database.field_types import ( + TextField, IntegerField, + DatetimeField, DateField, TimeField +) + +import pytest + + +def test_validate_null(): + field1 = IntegerField(None, nullable=False, is_auto_increment=False) + field2 = IntegerField(None, nullable=True, is_auto_increment=False) + + with pytest.raises(ValidationError): + ValidateNull.validate(None, field1) + + assert ValidateNull.validate(None, field2) is None + + +def test_validate_type(): + text1 = TextField(10, True, nullable=False) + text2 = TextField(10, True, nullable=True) + + with pytest.raises(ValidationError): + ValidateType.validate(None, text1) + + with pytest.raises(ValidationError): + ValidateType.validate(12, text1) + + with pytest.raises(ValidationError): + ValidateType.validate({1, 2, 3}, text1) + + with pytest.raises(ValidationError): + ValidateType.validate({1: 2}, text1) + + assert ValidateType.validate('123', text1) is None + assert ValidateType.validate(None, text2) is None + + +def test_validate_length(): + text1 = TextField(10, is_variable_length=True, nullable=False) + text2 = TextField(10, is_variable_length=False, nullable=False) + + assert ValidateLength.validate('1234567890', text1) is None + assert ValidateLength.validate('1234567890', text2) is None + + with pytest.raises(ValidationError): + ValidateLength.validate('1234567890*', text1) + + with pytest.raises(ValidationError): + ValidateLength.validate('123456789', text2) + + assert ValidateLength.validate('123456789', text1) is None + + +def test_validate_time(): + time_field = TimeField(False) + + assert ValidateTime.validate('00:00:00', time_field) is None + assert ValidateTime.validate('23:59:59', time_field) is None + + with pytest.raises(ValidationError): + ValidateTime.validate('24:00:00', time_field) + + with pytest.raises(ValidationError): + ValidateTime.validate('12:60:00', time_field) + + with pytest.raises(ValidationError): + ValidateTime.validate('12:00:60', time_field) + + with pytest.raises(ValidationError, match='Wrong time format'): + ValidateTime.validate('22:00', time_field) + + with pytest.raises(ValidationError, match='Wrong time format'): + ValidateTime.validate('22:00 12', time_field) + + with pytest.raises(ValidationError, match='Wrong time format'): + ValidateTime.validate('gsdfsd', time_field) + + +def test_validate_date(): + date_field = DateField(False) + + assert ValidateDate.validate('0001-01-01', date_field) is None + assert ValidateDate.validate('9999-12-31', date_field) is None + + with pytest.raises(ValidationError): + ValidateDate.validate('0000-00-00', date_field) + + with pytest.raises(ValidationError, match='Wrong day value'): + ValidateDate.validate('2019-02-29', date_field) + + assert ValidateDate.validate('2020-02-29', date_field) is None + + with pytest.raises(ValidationError): + ValidateDate.validate('2019-02-30', date_field) + + with pytest.raises(ValidationError, match='Wrong date format'): + ValidateDate.validate('17-03-21', date_field) + + with pytest.raises(ValidationError, match='Wrong date format'): + ValidateDate.validate('2002.03.12', date_field) + + with pytest.raises(ValidationError, match='Wrong date format'): + ValidateDate.validate('gsdfsd', date_field) + + +def test_validate_datetime(): + datetime_field = DatetimeField(False) + + assert ValidateDatetime.validate('2002-04-25 20:03:12', datetime_field) is None + + with pytest.raises(ValidationError): + ValidateDatetime.validate('2002-04-25_20:03:12', datetime_field) + + with pytest.raises(ValidationError): + ValidateDatetime.validate('2002 04 25 20:03:12', datetime_field) + + with pytest.raises(ValidationError): + ValidateDatetime.validate('2002-04-25 20:03', datetime_field) diff --git a/day9/task5_vue/webpack.config.js b/day9/task5_vue/webpack.config.js index 38efa45..6a7390a 100644 --- a/day9/task5_vue/webpack.config.js +++ b/day9/task5_vue/webpack.config.js @@ -20,6 +20,14 @@ module.exports = { 'vue-style-loader', 'css-loader' ] + }, + { + test: /\.less$/, + use: [ + 'vue-style-loader', + 'css-loader', + 'less-loader' + ] } ] }, |