├── .env_dummy ├── .flake8 ├── .gitignore ├── .pylintrc ├── .vscode ├── launch.json └── settings.json ├── Dockerfile ├── MySQL.sql ├── auth.py ├── config.ini-Dummy ├── docker-compose.yml ├── main.py ├── oAuthMain.py ├── read_event.py ├── readme.md ├── requirements.txt ├── user.py └── write_event.py /.env_dummy: -------------------------------------------------------------------------------- 1 | CLIENT_ID = client - id 2 | CLIENT_SECRET = client - secret 3 | REDIRECT_URI = "http://localhost:8501" 4 | host = "host" 5 | port = port_number 6 | database = "database_name" 7 | user = "root" 8 | password = "your_pwd" 9 | azure_event_key = "xxxxxxx" 10 | azure_event_endpoint = "xxxxxxxxx" 11 | azure_servicebus_conection_str = "XXXXX" 12 | azure_servicebus_queue_name = "XXXXXX" 13 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 66 3 | ignore = E501 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | config.ini 3 | .env 4 | __pycache__/user.cpython-39.pyc 5 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # A comma-separated list of package or module names from where C extensions may 4 | # be loaded. Extensions are loading into the active Python interpreter and may 5 | # run arbitrary code. 6 | extension-pkg-allow-list= 7 | 8 | # A comma-separated list of package or module names from where C extensions may 9 | # be loaded. Extensions are loading into the active Python interpreter and may 10 | # run arbitrary code. (This is an alternative name to extension-pkg-allow-list 11 | # for backward compatibility.) 12 | extension-pkg-whitelist= 13 | 14 | # Return non-zero exit code if any of these messages/categories are detected, 15 | # even if score is above --fail-under value. Syntax same as enable. Messages 16 | # specified are enabled, while categories only check already-enabled messages. 17 | fail-on= 18 | 19 | # Specify a score threshold to be exceeded before program exits with error. 20 | fail-under=10.0 21 | 22 | # Files or directories to be skipped. They should be base names, not paths. 23 | ignore=CVS 24 | 25 | # Add files or directories matching the regex patterns to the ignore-list. The 26 | # regex matches against paths and can be in Posix or Windows format. 27 | ignore-paths= 28 | 29 | # Files or directories matching the regex patterns are skipped. The regex 30 | # matches against base names, not paths. The default value ignores emacs file 31 | # locks 32 | ignore-patterns=^\.# 33 | 34 | # Python code to execute, usually for sys.path manipulation such as 35 | # pygtk.require(). 36 | #init-hook= 37 | 38 | # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the 39 | # number of processors available to use. 40 | jobs=1 41 | 42 | # Control the amount of potential inferred values when inferring a single 43 | # object. This can help the performance when dealing with large functions or 44 | # complex, nested conditions. 45 | limit-inference-results=100 46 | 47 | # List of plugins (as comma separated values of python module names) to load, 48 | # usually to register additional checkers. 49 | load-plugins= 50 | 51 | # Pickle collected data for later comparisons. 52 | persistent=yes 53 | 54 | # Minimum Python version to use for version dependent checks. Will default to 55 | # the version used to run pylint. 56 | py-version=3.9 57 | 58 | # Discover python modules and packages in the file system subtree. 59 | recursive=no 60 | 61 | # When enabled, pylint would attempt to guess common misconfiguration and emit 62 | # user-friendly hints instead of false-positive error messages. 63 | suggestion-mode=yes 64 | 65 | # Allow loading of arbitrary C extensions. Extensions are imported into the 66 | # active Python interpreter and may run arbitrary code. 67 | unsafe-load-any-extension=no 68 | 69 | 70 | [MESSAGES CONTROL] 71 | 72 | # Only show warnings with the listed confidence levels. Leave empty to show 73 | # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, 74 | # UNDEFINED. 75 | confidence= 76 | 77 | # Disable the message, report, category or checker with the given id(s). You 78 | # can either give multiple identifiers separated by comma (,) or put this 79 | # option multiple times (only on the command line, not in the configuration 80 | # file where it should appear only once). You can also use "--disable=all" to 81 | # disable everything first and then re-enable specific checks. For example, if 82 | # you want to run only the similarities checker, you can use "--disable=all 83 | # --enable=similarities". If you want to run only the classes checker, but have 84 | # no Warning level messages displayed, use "--disable=all --enable=classes 85 | # --disable=W". 86 | disable=raw-checker-failed, 87 | bad-inline-option, 88 | locally-disabled, 89 | file-ignored, 90 | suppressed-message, 91 | useless-suppression, 92 | deprecated-pragma, 93 | use-symbolic-message-instead, 94 | missing-function-docstring, 95 | missing-module-docstring, 96 | 97 | 98 | 99 | # Enable the message, report, category or checker with the given id(s). You can 100 | # either give multiple identifier separated by comma (,) or put this option 101 | # multiple time (only on the command line, not in the configuration file where 102 | # it should appear only once). See also the "--disable" option for examples. 103 | enable=c-extension-no-member 104 | 105 | 106 | [REPORTS] 107 | 108 | # Python expression which should return a score less than or equal to 10. You 109 | # have access to the variables 'fatal', 'error', 'warning', 'refactor', 110 | # 'convention', and 'info' which contain the number of messages in each 111 | # category, as well as 'statement' which is the total number of statements 112 | # analyzed. This score is used by the global evaluation report (RP0004). 113 | evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) 114 | 115 | # Template used to display messages. This is a python new-style format string 116 | # used to format the message information. See doc for all details. 117 | #msg-template= 118 | 119 | # Set the output format. Available formats are text, parseable, colorized, json 120 | # and msvs (visual studio). You can also give a reporter class, e.g. 121 | # mypackage.mymodule.MyReporterClass. 122 | output-format=text 123 | 124 | # Tells whether to display a full report or only the messages. 125 | reports=no 126 | 127 | # Activate the evaluation score. 128 | score=yes 129 | 130 | 131 | [REFACTORING] 132 | 133 | # Maximum number of nested blocks for function / method body 134 | max-nested-blocks=5 135 | 136 | # Complete name of functions that never returns. When checking for 137 | # inconsistent-return-statements if a never returning function is called then 138 | # it will be considered as an explicit return statement and no message will be 139 | # printed. 140 | never-returning-functions=sys.exit,argparse.parse_error 141 | 142 | 143 | [BASIC] 144 | 145 | # Naming style matching correct argument names. 146 | argument-naming-style=snake_case 147 | 148 | # Regular expression matching correct argument names. Overrides argument- 149 | # naming-style. If left empty, argument names will be checked with the set 150 | # naming style. 151 | #argument-rgx= 152 | 153 | # Naming style matching correct attribute names. 154 | attr-naming-style=snake_case 155 | 156 | # Regular expression matching correct attribute names. Overrides attr-naming- 157 | # style. If left empty, attribute names will be checked with the set naming 158 | # style. 159 | #attr-rgx= 160 | 161 | # Bad variable names which should always be refused, separated by a comma. 162 | bad-names=foo, 163 | bar, 164 | baz, 165 | toto, 166 | tutu, 167 | tata 168 | 169 | # Bad variable names regexes, separated by a comma. If names match any regex, 170 | # they will always be refused 171 | bad-names-rgxs= 172 | 173 | # Naming style matching correct class attribute names. 174 | class-attribute-naming-style=any 175 | 176 | # Regular expression matching correct class attribute names. Overrides class- 177 | # attribute-naming-style. If left empty, class attribute names will be checked 178 | # with the set naming style. 179 | #class-attribute-rgx= 180 | 181 | # Naming style matching correct class constant names. 182 | class-const-naming-style=UPPER_CASE 183 | 184 | # Regular expression matching correct class constant names. Overrides class- 185 | # const-naming-style. If left empty, class constant names will be checked with 186 | # the set naming style. 187 | #class-const-rgx= 188 | 189 | # Naming style matching correct class names. 190 | class-naming-style=PascalCase 191 | 192 | # Regular expression matching correct class names. Overrides class-naming- 193 | # style. If left empty, class names will be checked with the set naming style. 194 | #class-rgx= 195 | 196 | # Naming style matching correct constant names. 197 | const-naming-style=UPPER_CASE 198 | 199 | # Regular expression matching correct constant names. Overrides const-naming- 200 | # style. If left empty, constant names will be checked with the set naming 201 | # style. 202 | #const-rgx= 203 | 204 | # Minimum line length for functions/classes that require docstrings, shorter 205 | # ones are exempt. 206 | docstring-min-length=-1 207 | 208 | # Naming style matching correct function names. 209 | function-naming-style=snake_case 210 | 211 | # Regular expression matching correct function names. Overrides function- 212 | # naming-style. If left empty, function names will be checked with the set 213 | # naming style. 214 | #function-rgx= 215 | 216 | # Good variable names which should always be accepted, separated by a comma. 217 | good-names=i, 218 | j, 219 | k, 220 | ex, 221 | Run, 222 | _ 223 | 224 | # Good variable names regexes, separated by a comma. If names match any regex, 225 | # they will always be accepted 226 | good-names-rgxs= 227 | 228 | # Include a hint for the correct naming format with invalid-name. 229 | include-naming-hint=yes 230 | 231 | # Naming style matching correct inline iteration names. 232 | inlinevar-naming-style=any 233 | 234 | # Regular expression matching correct inline iteration names. Overrides 235 | # inlinevar-naming-style. If left empty, inline iteration names will be checked 236 | # with the set naming style. 237 | #inlinevar-rgx= 238 | 239 | # Naming style matching correct method names. 240 | method-naming-style=snake_case 241 | 242 | # Regular expression matching correct method names. Overrides method-naming- 243 | # style. If left empty, method names will be checked with the set naming style. 244 | #method-rgx= 245 | 246 | # Naming style matching correct module names. 247 | module-naming-style=snake_case 248 | 249 | # Regular expression matching correct module names. Overrides module-naming- 250 | # style. If left empty, module names will be checked with the set naming style. 251 | #module-rgx= 252 | 253 | # Colon-delimited sets of names that determine each other's naming style when 254 | # the name regexes allow several styles. 255 | name-group= 256 | 257 | # Regular expression which should only match function or class names that do 258 | # not require a docstring. 259 | no-docstring-rgx=^_ 260 | 261 | # List of decorators that produce properties, such as abc.abstractproperty. Add 262 | # to this list to register other decorators that produce valid properties. 263 | # These decorators are taken in consideration only for invalid-name. 264 | property-classes=abc.abstractproperty 265 | 266 | # Regular expression matching correct type variable names. If left empty, type 267 | # variable names will be checked with the set naming style. 268 | #typevar-rgx= 269 | 270 | # Naming style matching correct variable names. 271 | variable-naming-style=snake_case 272 | 273 | # Regular expression matching correct variable names. Overrides variable- 274 | # naming-style. If left empty, variable names will be checked with the set 275 | # naming style. 276 | #variable-rgx= 277 | 278 | 279 | [FORMAT] 280 | 281 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 282 | expected-line-ending-format= 283 | 284 | # Regexp for a line that is allowed to be longer than the limit. 285 | ignore-long-lines=^\s*(# )??$ 286 | 287 | # Number of spaces of indent required inside a hanging or continued line. 288 | indent-after-paren=4 289 | 290 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 291 | # tab). 292 | indent-string=' ' 293 | 294 | # Maximum number of characters on a single line. 295 | max-line-length=180 296 | 297 | # Maximum number of lines in a module. 298 | max-module-lines=1000 299 | 300 | # Allow the body of a class to be on the same line as the declaration if body 301 | # contains single statement. 302 | single-line-class-stmt=no 303 | 304 | # Allow the body of an if to be on the same line as the test if there is no 305 | # else. 306 | single-line-if-stmt=no 307 | 308 | 309 | [LOGGING] 310 | 311 | # The type of string formatting that logging methods do. `old` means using % 312 | # formatting, `new` is for `{}` formatting. 313 | logging-format-style=old 314 | 315 | # Logging modules to check that the string format arguments are in logging 316 | # function parameter format. 317 | logging-modules=logging 318 | 319 | 320 | [MISCELLANEOUS] 321 | 322 | # List of note tags to take in consideration, separated by a comma. 323 | notes=FIXME, 324 | XXX, 325 | TODO 326 | 327 | # Regular expression of note tags to take in consideration. 328 | #notes-rgx= 329 | 330 | 331 | [SIMILARITIES] 332 | 333 | # Comments are removed from the similarity computation 334 | ignore-comments=yes 335 | 336 | # Docstrings are removed from the similarity computation 337 | ignore-docstrings=yes 338 | 339 | # Imports are removed from the similarity computation 340 | ignore-imports=no 341 | 342 | # Signatures are removed from the similarity computation 343 | ignore-signatures=no 344 | 345 | # Minimum lines number of a similarity. 346 | min-similarity-lines=4 347 | 348 | 349 | [SPELLING] 350 | 351 | # Limits count of emitted suggestions for spelling mistakes. 352 | max-spelling-suggestions=4 353 | 354 | # Spelling dictionary name. Available dictionaries: none. To make it work, 355 | # install the 'python-enchant' package. 356 | spelling-dict= 357 | 358 | # List of comma separated words that should be considered directives if they 359 | # appear and the beginning of a comment and should not be checked. 360 | spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: 361 | 362 | # List of comma separated words that should not be checked. 363 | spelling-ignore-words= 364 | 365 | # A path to a file that contains the private dictionary; one word per line. 366 | spelling-private-dict-file= 367 | 368 | # Tells whether to store unknown words to the private dictionary (see the 369 | # --spelling-private-dict-file option) instead of raising a message. 370 | spelling-store-unknown-words=no 371 | 372 | 373 | [STRING] 374 | 375 | # This flag controls whether inconsistent-quotes generates a warning when the 376 | # character used as a quote delimiter is used inconsistently within a module. 377 | check-quote-consistency=no 378 | 379 | # This flag controls whether the implicit-str-concat should generate a warning 380 | # on implicit string concatenation in sequences defined over several lines. 381 | check-str-concat-over-line-jumps=no 382 | 383 | 384 | [TYPECHECK] 385 | 386 | # List of decorators that produce context managers, such as 387 | # contextlib.contextmanager. Add to this list to register other decorators that 388 | # produce valid context managers. 389 | contextmanager-decorators=contextlib.contextmanager 390 | 391 | # List of members which are set dynamically and missed by pylint inference 392 | # system, and so shouldn't trigger E1101 when accessed. Python regular 393 | # expressions are accepted. 394 | generated-members= 395 | 396 | # Tells whether missing members accessed in mixin class should be ignored. A 397 | # class is considered mixin if its name matches the mixin-class-rgx option. 398 | ignore-mixin-members=yes 399 | 400 | # Tells whether to warn about missing members when the owner of the attribute 401 | # is inferred to be None. 402 | ignore-none=yes 403 | 404 | # This flag controls whether pylint should warn about no-member and similar 405 | # checks whenever an opaque object is returned when inferring. The inference 406 | # can return multiple potential results while evaluating a Python object, but 407 | # some branches might not be evaluated, which results in partial inference. In 408 | # that case, it might be useful to still emit no-member and other checks for 409 | # the rest of the inferred objects. 410 | ignore-on-opaque-inference=yes 411 | 412 | # List of class names for which member attributes should not be checked (useful 413 | # for classes with dynamically set attributes). This supports the use of 414 | # qualified names. 415 | ignored-classes=optparse.Values,thread._local,_thread._local 416 | 417 | # List of module names for which member attributes should not be checked 418 | # (useful for modules/projects where namespaces are manipulated during runtime 419 | # and thus existing member attributes cannot be deduced by static analysis). It 420 | # supports qualified module names, as well as Unix pattern matching. 421 | ignored-modules= 422 | 423 | # Show a hint with possible names when a member name was not found. The aspect 424 | # of finding the hint is based on edit distance. 425 | missing-member-hint=yes 426 | 427 | # The minimum edit distance a name should have in order to be considered a 428 | # similar match for a missing member name. 429 | missing-member-hint-distance=1 430 | 431 | # The total number of similar names that should be taken in consideration when 432 | # showing a hint for a missing member. 433 | missing-member-max-choices=1 434 | 435 | # Regex pattern to define which classes are considered mixins ignore-mixin- 436 | # members is set to 'yes' 437 | mixin-class-rgx=.*[Mm]ixin 438 | 439 | # List of decorators that change the signature of a decorated function. 440 | signature-mutators= 441 | 442 | 443 | [VARIABLES] 444 | 445 | # List of additional names supposed to be defined in builtins. Remember that 446 | # you should avoid defining new builtins when possible. 447 | additional-builtins= 448 | 449 | # Tells whether unused global variables should be treated as a violation. 450 | allow-global-unused-variables=no 451 | 452 | # List of names allowed to shadow builtins 453 | allowed-redefined-builtins= 454 | 455 | # List of strings which can identify a callback function by name. A callback 456 | # name must start or end with one of those strings. 457 | callbacks=cb_, 458 | _cb 459 | 460 | # A regular expression matching the name of dummy variables (i.e. expected to 461 | # not be used). 462 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 463 | 464 | # Argument names that match this expression will be ignored. Default to name 465 | # with leading underscore. 466 | ignored-argument-names=_.*|^ignored_|^unused_ 467 | 468 | # Tells whether we should check for unused import in __init__ files. 469 | init-import=no 470 | 471 | # List of qualified module names which can have objects that can redefine 472 | # builtins. 473 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io 474 | 475 | 476 | [CLASSES] 477 | 478 | # Warn about protected attribute access inside special methods 479 | check-protected-access-in-special-methods=no 480 | 481 | # List of method names used to declare (i.e. assign) instance attributes. 482 | defining-attr-methods=__init__, 483 | __new__, 484 | setUp, 485 | __post_init__ 486 | 487 | # List of member names, which should be excluded from the protected access 488 | # warning. 489 | exclude-protected=_asdict, 490 | _fields, 491 | _replace, 492 | _source, 493 | _make 494 | 495 | # List of valid names for the first argument in a class method. 496 | valid-classmethod-first-arg=cls 497 | 498 | # List of valid names for the first argument in a metaclass class method. 499 | valid-metaclass-classmethod-first-arg=cls 500 | 501 | 502 | [DESIGN] 503 | 504 | # List of regular expressions of class ancestor names to ignore when counting 505 | # public methods (see R0903) 506 | exclude-too-few-public-methods= 507 | 508 | # List of qualified class names to ignore when counting class parents (see 509 | # R0901) 510 | ignored-parents= 511 | 512 | # Maximum number of arguments for function / method. 513 | max-args=5 514 | 515 | # Maximum number of attributes for a class (see R0902). 516 | max-attributes=7 517 | 518 | # Maximum number of boolean expressions in an if statement (see R0916). 519 | max-bool-expr=5 520 | 521 | # Maximum number of branch for function / method body. 522 | max-branches=12 523 | 524 | # Maximum number of locals for function / method body. 525 | max-locals=15 526 | 527 | # Maximum number of parents for a class (see R0901). 528 | max-parents=7 529 | 530 | # Maximum number of public methods for a class (see R0904). 531 | max-public-methods=20 532 | 533 | # Maximum number of return / yield for function / method body. 534 | max-returns=6 535 | 536 | # Maximum number of statements in function / method body. 537 | max-statements=50 538 | 539 | # Minimum number of public methods for a class (see R0903). 540 | min-public-methods=2 541 | 542 | 543 | [IMPORTS] 544 | 545 | # List of modules that can be imported at any level, not just the top level 546 | # one. 547 | allow-any-import-level= 548 | 549 | # Allow wildcard imports from modules that define __all__. 550 | allow-wildcard-with-all=no 551 | 552 | # Analyse import fallback blocks. This can be used to support both Python 2 and 553 | # 3 compatible code, which means that the block might have code that exists 554 | # only in one or another interpreter, leading to false positives when analysed. 555 | analyse-fallback-blocks=no 556 | 557 | # Deprecated modules which should not be used, separated by a comma. 558 | deprecated-modules= 559 | 560 | # Output a graph (.gv or any supported image format) of external dependencies 561 | # to the given file (report RP0402 must not be disabled). 562 | ext-import-graph= 563 | 564 | # Output a graph (.gv or any supported image format) of all (i.e. internal and 565 | # external) dependencies to the given file (report RP0402 must not be 566 | # disabled). 567 | import-graph= 568 | 569 | # Output a graph (.gv or any supported image format) of internal dependencies 570 | # to the given file (report RP0402 must not be disabled). 571 | int-import-graph= 572 | 573 | # Force import order to recognize a module as part of the standard 574 | # compatibility libraries. 575 | known-standard-library= 576 | 577 | # Force import order to recognize a module as part of a third party library. 578 | known-third-party=enchant 579 | 580 | # Couples of modules and preferred modules, separated by a comma. 581 | preferred-modules= 582 | 583 | 584 | [EXCEPTIONS] 585 | 586 | # Exceptions that will emit a warning when being caught. Defaults to 587 | # "BaseException, Exception". 588 | overgeneral-exceptions=BaseException, 589 | Exception 590 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Current File", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal", 13 | "justMyCode": true 14 | }, 15 | { 16 | "name": "Streamlit", 17 | "type": "python", 18 | "request": "launch", 19 | "program": "C://Python39//Scripts//streamlit.exe", 20 | "console": "integratedTerminal", 21 | "justMyCode": true, 22 | "args": [ 23 | "run", 24 | "main.py" 25 | ] 26 | } 27 | 28 | ] 29 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.formatting.provider": "autopep8", 3 | "python.linting.enabled": true, 4 | "python.linting.pylintEnabled": true, 5 | 6 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | from python:3.9.0 2 | expose 8501 3 | cmd mkdir -p /app 4 | WORKDIR /app 5 | copy requirements.txt ./requirements.txt 6 | run pip3 install -r requirements.txt 7 | copy . . 8 | ENTRYPOINT ["streamlit", "run"] 9 | CMD ["main.py"] -------------------------------------------------------------------------------- /MySQL.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE `streamlit` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; 2 | 3 | 4 | CREATE TABLE `Users` ( 5 | `UserId` varchar(255) NOT NULL, 6 | `Password` varchar(32) NOT NULL, 7 | `CreatedTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 8 | `Active` bit(1) DEFAULT NULL, 9 | PRIMARY KEY (`UserId`), 10 | UNIQUE KEY `UserId_UNIQUE` (`UserId`) 11 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 12 | 13 | 14 | DELIMITER $$ 15 | CREATE PROCEDURE `CheckUser`( IN _userId varchar(255), IN _password varchar(32), out _result int ) 16 | BEGIN 17 | 18 | declare _User varchar(255); 19 | SELECT UserId into _User FROM Users WHERE `Password` = _password AND UserId = _userId AND `Active` = 1; 20 | IF (isnull(_User)) THEN 21 | BEGIN 22 | SET _result = 0; 23 | END; 24 | ELSE 25 | BEGIN 26 | SET _result = 1; 27 | END; 28 | END IF; 29 | END$$ 30 | DELIMITER ; 31 | 32 | 33 | DELIMITER $$ 34 | CREATE PROCEDURE `SaveUser`( IN _userId VARCHAR (255), 35 | IN _password VARCHAR(32)) 36 | BEGIN 37 | IF EXISTS 38 | (SELECT * FROM Users 39 | WHERE UserId = _userId) THEN 40 | BEGIN 41 | UPDATE Users 42 | SET 43 | Password = _password, CreatedTime = now() 44 | WHERE UserId = _userId and Active = 1; 45 | END; 46 | ELSE 47 | INSERT INTO Users (UserId, password, CreatedTime, Active) Values ( _userId, _password, now(), 1); 48 | END if; 49 | 50 | SELECT * FROM Users WHERE UserId = _userId; 51 | 52 | END$$ 53 | DELIMITER ; 54 | 55 | /* Insert dummy data */ 56 | DELIMITER ; 57 | CALL SaveUser('admin','admin') -------------------------------------------------------------------------------- /auth.py: -------------------------------------------------------------------------------- 1 | # IMPORTING LIBRARIES 2 | import os 3 | from numpy import void 4 | import streamlit as st 5 | import asyncio 6 | # https://frankie567.github.io/httpx-oauth/oauth2/ 7 | from httpx_oauth.clients.google import GoogleOAuth2 8 | from dotenv import load_dotenv 9 | 10 | load_dotenv('.env') 11 | 12 | CLIENT_ID = os.environ['CLIENT_ID'] 13 | CLIENT_SECRET = os.environ['CLIENT_SECRET'] 14 | REDIRECT_URI = os.environ['REDIRECT_URI'] 15 | 16 | 17 | async def get_authorization_url(client: GoogleOAuth2, redirect_uri: str): 18 | authorization_url = await client.get_authorization_url(redirect_uri, scope=["profile", "email"]) 19 | return authorization_url 20 | 21 | 22 | async def get_access_token(client: GoogleOAuth2, redirect_uri: str, code: str): 23 | token = await client.get_access_token(code, redirect_uri) 24 | return token 25 | 26 | 27 | async def get_email(client: GoogleOAuth2, token: str): 28 | user_id, user_email = await client.get_id_email(token) 29 | return user_id, user_email 30 | 31 | 32 | def get_login_str(): 33 | client: GoogleOAuth2 = GoogleOAuth2(CLIENT_ID, CLIENT_SECRET) 34 | authorization_url = asyncio.run( 35 | get_authorization_url(client, REDIRECT_URI)) 36 | return f''' < a target = "_self" href = "{authorization_url}" > Google login < /a > ''' 37 | 38 | 39 | def display_user() -> void: 40 | client: GoogleOAuth2 = GoogleOAuth2(CLIENT_ID, CLIENT_SECRET) 41 | # get the code from the url 42 | code = st.experimental_get_query_params()['code'] 43 | token = asyncio.run(get_access_token( 44 | client, REDIRECT_URI, code)) 45 | user_id, user_email = asyncio.run( 46 | get_email(client, token['access_token'])) 47 | st.write( 48 | f"You're logged in as {user_email} and id is {user_id}") 49 | -------------------------------------------------------------------------------- /config.ini-Dummy: -------------------------------------------------------------------------------- 1 | [MySQL] 2 | host = "127.0.0.1" 3 | port = 3306 4 | database = "streamlit" 5 | user = "root" 6 | password = "XXXXXXX" -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | streamlit: 3 | build: 4 | dockerfile: ./Dockerfile 5 | context: ./ 6 | ports: 7 | - "8081:8501" -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from user import login 3 | # Third change in april 4 | 5 | headerSection = st.container() 6 | mainSection = st.container() 7 | loginSection = st.container() 8 | logOutSection = st.container() 9 | 10 | def show_main_page(): 11 | with mainSection: 12 | dataFile = st.text_input("Enter your Test file name: ") 13 | Topics = st.text_input("Enter your Model Name: ") 14 | ModelVersion = st.text_input("Enter your Model Version: ") 15 | processingClicked = st.button ("Start Processing", key="processing") 16 | if processingClicked: 17 | st.balloons() 18 | 19 | def LoggedOut_Clicked(): 20 | st.session_state['loggedIn'] = False 21 | 22 | def show_logout_page(): 23 | loginSection.empty(); 24 | with logOutSection: 25 | st.button ("Log Out", key="logout", on_click=LoggedOut_Clicked) 26 | 27 | def LoggedIn_Clicked(userName, password): 28 | if login(userName, password): 29 | st.session_state['loggedIn'] = True 30 | else: 31 | st.session_state['loggedIn'] = False; 32 | st.error("Invalid user name or password") 33 | 34 | def show_login_page(): 35 | with loginSection: 36 | if st.session_state['loggedIn'] == False: 37 | userName = st.text_input (label="", value="", placeholder="Enter your user name") 38 | password = st.text_input (label="", value="",placeholder="Enter password", type="password") 39 | st.button ("Login", on_click=LoggedIn_Clicked, args= (userName, password)) 40 | 41 | 42 | with headerSection: 43 | st.title("Streamlit Application") 44 | #first run will have nothing in session_state 45 | if 'loggedIn' not in st.session_state: 46 | st.session_state['loggedIn'] = False 47 | show_login_page() 48 | else: 49 | if st.session_state['loggedIn']: 50 | show_logout_page() 51 | show_main_page() 52 | else: 53 | show_login_page() 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /oAuthMain.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from auth import * 3 | 4 | 5 | if __name__ == '__main__': 6 | st.title("Streamlit Oauth Login") 7 | st.write(get_login_str(), unsafe_allow_html=True) 8 | 9 | if st.button("display user"): 10 | display_user() -------------------------------------------------------------------------------- /read_event.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | from azure.eventgrid import EventGridEvent 4 | from azure.servicebus import ServiceBusClient 5 | from dotenv import load_dotenv 6 | # 7 | # https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-python-how-to-use-queues 8 | 9 | load_dotenv('.env') 10 | 11 | connection_str = os.environ['azure_servicebus_conection_str'] 12 | queue_name = os.environ['azure_servicebus_queue_name'] 13 | 14 | 15 | if __name__ == '__main__': 16 | try: 17 | with ServiceBusClient.from_connection_string(connection_str) as sb_client: 18 | receiver = sb_client.get_queue_receiver(queue_name=queue_name) 19 | with receiver: 20 | for message in receiver: 21 | event = json.loads(str(message)) 22 | print(f"Event: {event['data']}") 23 | receiver.complete_message(message) # mark message as complete 24 | 25 | except: 26 | print("Error: No message received") 27 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | docker build -f Dockerfile -t streamlit-app:latest . 3 | docker run -p 8501:8501 streamlit-app:latest 4 | 5 | # OAuth 6 | For OAuth flow, run oAuthMain.py file 7 | 8 | # OAuth 9 | For OAuth flow, run oAuthMain.py file 10 | 11 | # Azure Event Grid 12 | pip install azure-eventgrid 13 | # AWS 14 | 15 | Down load the AWS CLI 16 | https://docs.aws.amazon.com/AmazonECR/latest/userguide/getting-started-cli.html 17 | 18 | ## build the image 19 | docker build -f Dockerfile -t streamlit-app:latest . 20 | ## tag the image 21 | docker tag streamlit-app:latest public.ecr.aws/e3w4k9h3/streamlit:latest 22 | 23 | ## Push the image 24 | docker push public.ecr.aws/e3w4k9h3/streamlit-app:latest -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | 2 | httpx_oauth==0.5.0 3 | mysql-connector-python==8.0.28 4 | pandas==1.3.4 5 | python-dotenv==0.20.0 6 | streamlit==1.8.0 7 | 8 | -------------------------------------------------------------------------------- /user.py: -------------------------------------------------------------------------------- 1 | # pip install mysql-connector-python 2 | import mysql.connector 3 | from configparser import ConfigParser 4 | from torch import _fake_quantize_per_tensor_affine_cachemask_tensor_qparams 5 | CNX: mysql.connector.connect 6 | 7 | 8 | def login(userName: str, password: str) -> bool: 9 | if (userName is None): 10 | return False 11 | args = [userName, password, 0] 12 | result_args = execute_sql_query("CheckUser", args) 13 | return (result_args[2] == 1) 14 | 15 | def execute_sql_query(query, args): 16 | global CNX 17 | if (CNX is None): 18 | config = ConfigParser() 19 | config. read("config.ini") 20 | _host = config.get('MySQL', 'host') 21 | _port = config.get('MySQL', 'port') 22 | _database = config.get('MySQL', 'database') 23 | _user = config.get('MySQL', 'user') 24 | _password = config.get('MySQL', 'password') 25 | CNX = mysql.connector.connect(host=_host, database=_database, 26 | user=_user, passwd=_password, port=_port) 27 | 28 | with CNX.cursor() as cur: 29 | return cur.callproc(query, args) 30 | -------------------------------------------------------------------------------- /write_event.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from dotenv import load_dotenv 3 | import os 4 | from azure.core.credentials import AzureKeyCredential 5 | from azure.eventgrid import EventGridPublisherClient, EventGridEvent 6 | import json 7 | import time 8 | 9 | 10 | def create_data() -> str: 11 | data = {} 12 | data['producer'] = 'python app-1' 13 | data['subscriber'] = 'python app-2' 14 | data['timestamp'] = datetime.datetime.now().isoformat() 15 | return json.dumps(data) 16 | 17 | 18 | load_dotenv('.env') 19 | 20 | azure_event_key = os.environ['azure_event_key'] 21 | azure_event_endpoint = os.environ['azure_event_endpoint'] 22 | 23 | 24 | def send_event(event): 25 | endpoint = azure_event_endpoint 26 | credential = AzureKeyCredential(azure_event_key) 27 | client = EventGridPublisherClient(endpoint, credential) 28 | client.send(event) 29 | print(".") 30 | 31 | 32 | def create_event(event_data: str) -> EventGridEvent: 33 | return EventGridEvent( 34 | data=event_data, 35 | subject="spider-1", 36 | event_type="SpiderEvent", 37 | data_version="1.0" 38 | ) 39 | 40 | 41 | if __name__ == '__main__': 42 | while True: 43 | send_event(create_event(create_data())) 44 | time.sleep(4) # sleep for 4 seconds 45 | --------------------------------------------------------------------------------