diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 294ed654f3..ea173d2e10 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -90,7 +90,7 @@ jobs: - name: Cache extensions 5.3 - 5.6 if: matrix.php < '7.0' - uses: actions/cache@v3 + uses: actions/cache@v3.0.4 with: path: ${{ steps.cache-env-php5.outputs.dir }} key: ${{ steps.cache-env-php5.outputs.key }} @@ -98,7 +98,7 @@ jobs: - name: Cache extensions 7.0 - 8.0 if: matrix.php >= '7.0' - uses: actions/cache@v3 + uses: actions/cache@v3.0.4 with: path: ${{ steps.cache-env-php7.outputs.dir }} key: ${{ steps.cache-env-php7.outputs.key }} @@ -121,7 +121,7 @@ jobs: run: echo "COMPOSER_CACHE_DIR=~\AppData\Local\Composer" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Cache dependencies installed with composer - uses: actions/cache@v3 + uses: actions/cache@v3.0.4 with: path: ${{ env.COMPOSER_CACHE_DIR }} key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000000..b0dedc42e0 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 0000000000..5a9be2cb32 --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,49 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# ESLint is a tool for identifying and reporting on patterns +# found in ECMAScript/JavaScript code. +# More details at https://github.com/eslint/eslint +# and https://eslint.org + +name: ESLint + +on: + push: + branches: [ "master", customizations ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '29 23 * * 0' + +jobs: + eslint: + name: Run eslint scanning + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install ESLint + run: | + npm install eslint@8.10.0 + npm install @microsoft/eslint-formatter-sarif@2.1.7 + + - name: Run ESLint + run: npx eslint . + --config .eslintrc.js + --ext .js,.jsx,.ts,.tsx + --format @microsoft/eslint-formatter-sarif + --output-file eslint-results.sarif + continue-on-error: true + + - name: Upload analysis results to GitHub + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: eslint-results.sarif + wait-for-processing: true diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000000..a7d195fc73 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,39 @@ +name: PHP Composer + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + + # - name: Run test suite + # run: composer run-script test diff --git a/.github/workflows/phpmd.yml b/.github/workflows/phpmd.yml new file mode 100644 index 0000000000..ac37909ab1 --- /dev/null +++ b/.github/workflows/phpmd.yml @@ -0,0 +1,56 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# PHPMD is a spin-off project of PHP Depend and +# aims to be a PHP equivalent of the well known Java tool PMD. +# What PHPMD does is: It takes a given PHP source code base +# and look for several potential problems within that source. +# These problems can be things like: +# Possible bugs +# Suboptimal code +# Overcomplicated expressions +# Unused parameters, methods, properties +# More details at https://phpmd.org/ + +name: PHPMD + +on: + push: + branches: [ "master", customizations ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '28 2 * * 6' + +permissions: + contents: read + +jobs: + PHPMD: + name: Run PHPMD scanning + runs-on: ubuntu-latest + permissions: + contents: read # for checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@aa1fe473f9c687b6fb896056d771232c0bc41161 + with: + coverage: none + tools: phpmd + + - name: Run PHPMD + run: phpmd . sarif codesize --reportfile phpmd-results.sarif + continue-on-error: true + + - name: Upload analysis results to GitHub + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: phpmd-results.sarif + wait-for-processing: true diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml new file mode 100644 index 0000000000..acee01e2b2 --- /dev/null +++ b/.github/workflows/super-linter.yml @@ -0,0 +1,29 @@ +# This workflow executes several linters on changed files based on languages used in your code base whenever +# you push a code or open a pull request. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/github/super-linter +name: Lint Code Base + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] +jobs: + run-lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + # Full git history is needed to get a proper list of changed files within `super-linter` + fetch-depth: 0 + + - name: Lint Code Base + uses: github/super-linter@v4 + env: + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: "master" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 981a61ac76..e8380af5ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *.iml *.ipr *.iws -.idea/ nbproject/ nbactions.xml nb-configuration.xml diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml new file mode 100644 index 0000000000..581048db0a --- /dev/null +++ b/.idea/dbnavigator.xml @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000000..aeaa3bfe1b --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 0000000000..02b915b85f --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000..d829d01a18 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000000..515367d977 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000000..5a6030d1f2 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/sonarlint/issuestore/index.pb b/.idea/sonarlint/issuestore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.idea/sonarlint/securityhotspotstore/index.pb b/.idea/sonarlint/securityhotspotstore/index.pb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..ba36ad6c53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000000..83c45ace0d --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,286 @@ + + + + + + + + + + + + $PROJECT_DIR$/composer.json + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1654806987020 + + + 1654813671556 + + + 1676094615405 + + + 1678161524201 + + + 1678489834506 + + + 1678491148691 + + + 1678493604551 + + + 1678495277501 + + + 1678495757614 + + + 1678495832267 + + + + + + + + + + + + + *

hint text

+ * + *
+ * + * + *

hint text

+ *
+ *
+ * + * + *

hint text

+ *
+ * + * + * The above code will render the labels and input fields in separate lines. + * In order to render them in the same line, please use the "wide" form as follows, + * + *
+ * ...... + *
+ * + * @author Qiang Xue + * @link https://www.yiiframework.com/ + * @copyright 2008-2010 Yii Software LLC + * @license https://www.yiiframework.com/license/ + */ + +div.form +{ +} + +div.form input, +div.form textarea, +div.form select +{ + margin: 0.2em 0 0.5em 0; +} + +div.form fieldset +{ + border: 1px solid #DDD; + padding: 10px; + margin: 0 0 10px 0; + -moz-border-radius:7px; +} + +div.form label +{ + font-weight: bold; + font-size: 0.9em; + display: block; +} + +div.form .row +{ + margin: 5px 0; +} + +div.form .hint +{ + margin: 0; + padding: 0; + color: #999; +} + +div.form .note +{ + font-style: italic; +} + +div.form span.required +{ + color: red; +} + +div.form div.error label:first-child, +div.form label.error, +div.form span.error +{ + color: #C00; +} + +div.form div.error input, +div.form div.error textarea, +div.form div.error select, +div.form input.error, +div.form textarea.error, +div.form select.error +{ + background: #FEE; + border-color: #C00; +} + +div.form div.success input, +div.form div.success textarea, +div.form div.success select, +div.form input.success, +div.form textarea.success, +div.form select.success +{ + background: #E6EFC2; + border-color: #C6D880; +} + +div.form div.success label +{ + color: inherit; +} + +div.form .errorSummary +{ + border: 2px solid #C00; + padding: 7px 7px 12px 7px; + margin: 0 0 20px 0; + background: #FEE; + font-size: 0.9em; +} + +div.form .errorMessage +{ + color: red; + font-size: 0.9em; +} + +div.form .errorSummary p +{ + margin: 0; + padding: 5px; +} + +div.form .errorSummary ul +{ + margin: 0; + padding: 0 0 0 20px; +} + +div.wide.form label +{ + float: left; + margin-right: 10px; + position: relative; + text-align: right; + width: 100px; +} + +div.wide.form .row +{ + clear: left; +} + +div.wide.form .buttons, div.wide.form .hint, div.wide.form .errorMessage +{ + clear: left; + padding-left: 110px; +} diff --git a/testdrive/css/ie.css b/testdrive/css/ie.css new file mode 100644 index 0000000000..f01539959a --- /dev/null +++ b/testdrive/css/ie.css @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 1.0.1 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* ie.css */ +body {text-align:center;} +.container {text-align:left;} +* html .column, * html .span-1, * html .span-2, * html .span-3, * html .span-4, * html .span-5, * html .span-6, * html .span-7, * html .span-8, * html .span-9, * html .span-10, * html .span-11, * html .span-12, * html .span-13, * html .span-14, * html .span-15, * html .span-16, * html .span-17, * html .span-18, * html .span-19, * html .span-20, * html .span-21, * html .span-22, * html .span-23, * html .span-24 {display:inline;overflow-x:hidden;} +* html legend {margin:0px -8px 16px 0;padding:0;} +sup {vertical-align:text-top;} +sub {vertical-align:text-bottom;} +html>body p code {*white-space:normal;} +hr {margin:-8px auto 11px;} +img {-ms-interpolation-mode:bicubic;} +.clearfix, .container {display:inline-block;} +* html .clearfix, * html .container {height:1%;} +fieldset {padding-top:0;} +legend {margin-top:-0.2em;margin-bottom:1em;margin-left:-0.5em;} +textarea {overflow:auto;} +label {vertical-align:middle;position:relative;top:-0.25em;} +input.text, input.title, textarea {background-color:#fff;border:1px solid #bbb;} +input.text:focus, input.title:focus {border-color:#666;} +input.text, input.title, textarea, select {margin:0.5em 0;} +input.checkbox, input.radio {position:relative;top:.25em;} +form.inline div, form.inline p {vertical-align:middle;} +form.inline input.checkbox, form.inline input.radio, form.inline input.button, form.inline button {margin:0.5em 0;} +button, input.button {position:relative;top:0.25em;} \ No newline at end of file diff --git a/testdrive/css/main.css b/testdrive/css/main.css new file mode 100644 index 0000000000..13327b86f9 --- /dev/null +++ b/testdrive/css/main.css @@ -0,0 +1,229 @@ +body +{ + margin: 0; + padding: 0; + color: #555; + font: normal 10pt Arial,Helvetica,sans-serif; + background: #EFEFEF; +} + +#page +{ + margin-top: 5px; + margin-bottom: 5px; + background: white; + border: 1px solid #C9E0ED; +} + +#header +{ + margin: 0; + padding: 0; + border-top: 3px solid #C9E0ED; +} + +#content +{ + padding: 20px; +} + +#sidebar +{ + padding: 20px 20px 20px 0; +} + +#footer +{ + padding: 10px; + margin: 10px 20px; + font-size: 0.8em; + text-align: center; + border-top: 1px solid #C9E0ED; +} + +#logo +{ + padding: 10px 20px; + font-size: 200%; +} + +#mainmenu +{ + background:white url(bg.gif) repeat-x left top; +} + +#mainmenu ul +{ + padding:6px 20px 5px 20px; + margin:0px; +} + +#mainmenu ul li +{ + display: inline; +} + +#mainmenu ul li a +{ + color:#ffffff; + background-color:transparent; + font-size:12px; + font-weight:bold; + text-decoration:none; + padding:5px 8px; +} + +#mainmenu ul li a:hover, #mainmenu ul li.active a +{ + color: #6399cd; + background-color:#EFF4FA; + text-decoration:none; +} + +div.flash-error, div.flash-notice, div.flash-success +{ + padding:.8em; + margin-bottom:1em; + border:2px solid #ddd; +} + +div.flash-error +{ + background:#FBE3E4; + color:#8a1f11; + border-color:#FBC2C4; +} + +div.flash-notice +{ + background:#FFF6BF; + color:#514721; + border-color:#FFD324; +} + +div.flash-success +{ + background:#E6EFC2; + color:#264409; + border-color:#C6D880; +} + +div.flash-error a +{ + color:#8a1f11; +} + +div.flash-notice a +{ + color:#514721; +} + +div.flash-success a +{ + color:#264409; +} + +div.form .rememberMe label +{ + display: inline; +} + +div.view +{ + padding: 10px; + margin: 10px 0; + border: 1px solid #C9E0ED; +} + +div.breadcrumbs +{ + font-size: 0.9em; + padding: 5px 20px; +} + +div.breadcrumbs span +{ + font-weight: bold; +} + +div.search-form +{ + padding: 10px; + margin: 10px 0; + background: #eee; +} + +.portlet +{ + +} + +.portlet-decoration +{ + padding: 3px 8px; + background: #B7D6E7; + border-left: 5px solid #6FACCF; +} + +.portlet-title +{ + font-size: 12px; + font-weight: bold; + padding: 0; + margin: 0; + color: #298dcd; +} + +.portlet-content +{ + font-size:0.9em; + margin: 0 0 15px 0; + padding: 5px 8px; + background:#EFFDFF; +} + +.portlet-content ul +{ + list-style-image:none; + list-style-position:outside; + list-style-type:none; + margin: 0; + padding: 0; +} + +.portlet-content li +{ + padding: 2px 0 4px 0px; +} + +.operations +{ + list-style-type: none; + margin: 0; + padding: 0; +} + +.operations li +{ + padding-bottom: 2px; +} + +.operations li a +{ + font: bold 12px Arial; + color: #0066A4; + display: block; + padding: 2px 0 2px 8px; + line-height: 15px; + text-decoration: none; +} + +.operations li a:visited +{ + color: #0066A4; +} + +.operations li a:hover +{ + background: #80CFFF; +} \ No newline at end of file diff --git a/testdrive/css/print.css b/testdrive/css/print.css new file mode 100644 index 0000000000..bd79afdea5 --- /dev/null +++ b/testdrive/css/print.css @@ -0,0 +1,29 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 1.0.1 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* print.css */ +body {line-height:1.5;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;color:#000;background:none;font-size:10pt;} +.container {background:none;} +hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;} +hr.space {background:#fff;color:#fff;visibility:hidden;} +h1, h2, h3, h4, h5, h6 {font-family:"Helvetica Neue", Arial, "Lucida Grande", sans-serif;} +code {font:.9em "Courier New", Monaco, Courier, monospace;} +a img {border:none;} +p img.top {margin-top:0;} +blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;} +.small {font-size:.9em;} +.large {font-size:1.1em;} +.quiet {color:#999;} +.hide {display:none;} +a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;} +a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;} \ No newline at end of file diff --git a/testdrive/css/screen.css b/testdrive/css/screen.css new file mode 100644 index 0000000000..7824d077c3 --- /dev/null +++ b/testdrive/css/screen.css @@ -0,0 +1,238 @@ +/* ----------------------------------------------------------------------- + + + Blueprint CSS Framework 1.0.1 + http://blueprintcss.org + + * Copyright (c) 2007-Present. See LICENSE for more info. + * See README for instructions on how to use Blueprint. + * For credits and origins, see AUTHORS. + * This is a compressed file. See the sources in the 'src' directory. + +----------------------------------------------------------------------- */ + +/* reset.css */ +html {margin:0;padding:0;border:0;} +body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, dialog, figure, footer, header, hgroup, nav, section {margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline;} +article, aside, details, figcaption, figure, dialog, footer, header, hgroup, menu, nav, section {display:block;} +body {line-height:1.5;background:white;} +table {border-collapse:separate;border-spacing:0;} +caption, th, td {text-align:left;font-weight:normal;float:none !important;} +table, th, td {vertical-align:middle;} +blockquote:before, blockquote:after, q:before, q:after {content:'';} +blockquote, q {quotes:"" "";} +a img {border:none;} +:focus {outline:0;} + +/* typography.css */ +html {font-size:100.01%;} +body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Arial, Helvetica, sans-serif;} +h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} +h1 {font-size:2em;line-height:1;margin-bottom:0.5em;} +h2 {font-size:1.6em;margin-bottom:0.75em;} +h3 {font-size:1.4em;line-height:1;margin-bottom:1em;} +h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;} +h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} +h6 {font-size:1em;font-weight:bold;} +h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} +p {margin:0 0 1.5em;} +.left {float:left !important;} +p .left {margin:1.5em 1.5em 1.5em 0;padding:0;} +.right {float:right !important;} +p .right {margin:1.5em 0 1.5em 1.5em;padding:0;} +a:focus, a:hover {color:#09f;} +a {color:#06c;text-decoration:underline;} +blockquote {margin:1.5em;color:#666;font-style:italic;} +strong, dfn {font-weight:bold;} +em, dfn {font-style:italic;} +sup, sub {line-height:0;} +abbr, acronym {border-bottom:1px dotted #666;} +address {margin:0 0 1.5em;font-style:italic;} +del {color:#666;} +pre {margin:1.5em 0;white-space:pre;} +pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} +li ul, li ol {margin:0;} +ul, ol {margin:0 1.5em 1.5em 0;padding-left:1.5em;} +ul {list-style-type:disc;} +ol {list-style-type:decimal;} +dl {margin:0 0 1.5em 0;} +dl dt {font-weight:bold;} +dd {margin-left:1.5em;} +table {margin-bottom:1.4em;width:100%;} +th {font-weight:bold;} +thead th {background:#c3d9ff;} +th, td, caption {padding:4px 10px 4px 5px;} +tfoot {font-style:italic;} +caption {background:#eee;} +.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} +.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} +.hide {display:none;} +.quiet {color:#666;} +.loud {color:#000;} +.highlight {background:#ff0;} +.added {background:#060;color:#fff;} +.removed {background:#900;color:#fff;} +.first {margin-left:0;padding-left:0;} +.last {margin-right:0;padding-right:0;} +.top {margin-top:0;padding-top:0;} +.bottom {margin-bottom:0;padding-bottom:0;} + +/* grid.css */ +.container {width:950px;margin:0 auto;} +.column, .span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {float:left;margin-right:10px;} +.last {margin-right:0;} +.span-1 {width:30px;} +.span-2 {width:70px;} +.span-3 {width:110px;} +.span-4 {width:150px;} +.span-5 {width:190px;} +.span-6 {width:230px;} +.span-7 {width:270px;} +.span-8 {width:310px;} +.span-9 {width:350px;} +.span-10 {width:390px;} +.span-11 {width:430px;} +.span-12 {width:470px;} +.span-13 {width:510px;} +.span-14 {width:550px;} +.span-15 {width:590px;} +.span-16 {width:630px;} +.span-17 {width:670px;} +.span-18 {width:710px;} +.span-19 {width:750px;} +.span-20 {width:790px;} +.span-21 {width:830px;} +.span-22 {width:870px;} +.span-23 {width:910px;} +.span-24 {width:950px;margin-right:0;} +input.span-1, textarea.span-1, input.span-2, textarea.span-2, input.span-3, textarea.span-3, input.span-4, textarea.span-4, input.span-5, textarea.span-5, input.span-6, textarea.span-6, input.span-7, textarea.span-7, input.span-8, textarea.span-8, input.span-9, textarea.span-9, input.span-10, textarea.span-10, input.span-11, textarea.span-11, input.span-12, textarea.span-12, input.span-13, textarea.span-13, input.span-14, textarea.span-14, input.span-15, textarea.span-15, input.span-16, textarea.span-16, input.span-17, textarea.span-17, input.span-18, textarea.span-18, input.span-19, textarea.span-19, input.span-20, textarea.span-20, input.span-21, textarea.span-21, input.span-22, textarea.span-22, input.span-23, textarea.span-23, input.span-24, textarea.span-24 {border-left-width:1px;border-right-width:1px;padding-left:5px;padding-right:5px;} +input.span-1, textarea.span-1 {width:18px;} +input.span-2, textarea.span-2 {width:58px;} +input.span-3, textarea.span-3 {width:98px;} +input.span-4, textarea.span-4 {width:138px;} +input.span-5, textarea.span-5 {width:178px;} +input.span-6, textarea.span-6 {width:218px;} +input.span-7, textarea.span-7 {width:258px;} +input.span-8, textarea.span-8 {width:298px;} +input.span-9, textarea.span-9 {width:338px;} +input.span-10, textarea.span-10 {width:378px;} +input.span-11, textarea.span-11 {width:418px;} +input.span-12, textarea.span-12 {width:458px;} +input.span-13, textarea.span-13 {width:498px;} +input.span-14, textarea.span-14 {width:538px;} +input.span-15, textarea.span-15 {width:578px;} +input.span-16, textarea.span-16 {width:618px;} +input.span-17, textarea.span-17 {width:658px;} +input.span-18, textarea.span-18 {width:698px;} +input.span-19, textarea.span-19 {width:738px;} +input.span-20, textarea.span-20 {width:778px;} +input.span-21, textarea.span-21 {width:818px;} +input.span-22, textarea.span-22 {width:858px;} +input.span-23, textarea.span-23 {width:898px;} +input.span-24, textarea.span-24 {width:938px;} +.append-1 {padding-right:40px;} +.append-2 {padding-right:80px;} +.append-3 {padding-right:120px;} +.append-4 {padding-right:160px;} +.append-5 {padding-right:200px;} +.append-6 {padding-right:240px;} +.append-7 {padding-right:280px;} +.append-8 {padding-right:320px;} +.append-9 {padding-right:360px;} +.append-10 {padding-right:400px;} +.append-11 {padding-right:440px;} +.append-12 {padding-right:480px;} +.append-13 {padding-right:520px;} +.append-14 {padding-right:560px;} +.append-15 {padding-right:600px;} +.append-16 {padding-right:640px;} +.append-17 {padding-right:680px;} +.append-18 {padding-right:720px;} +.append-19 {padding-right:760px;} +.append-20 {padding-right:800px;} +.append-21 {padding-right:840px;} +.append-22 {padding-right:880px;} +.append-23 {padding-right:920px;} +.prepend-1 {padding-left:40px;} +.prepend-2 {padding-left:80px;} +.prepend-3 {padding-left:120px;} +.prepend-4 {padding-left:160px;} +.prepend-5 {padding-left:200px;} +.prepend-6 {padding-left:240px;} +.prepend-7 {padding-left:280px;} +.prepend-8 {padding-left:320px;} +.prepend-9 {padding-left:360px;} +.prepend-10 {padding-left:400px;} +.prepend-11 {padding-left:440px;} +.prepend-12 {padding-left:480px;} +.prepend-13 {padding-left:520px;} +.prepend-14 {padding-left:560px;} +.prepend-15 {padding-left:600px;} +.prepend-16 {padding-left:640px;} +.prepend-17 {padding-left:680px;} +.prepend-18 {padding-left:720px;} +.prepend-19 {padding-left:760px;} +.prepend-20 {padding-left:800px;} +.prepend-21 {padding-left:840px;} +.prepend-22 {padding-left:880px;} +.prepend-23 {padding-left:920px;} +.border {padding-right:4px;margin-right:5px;border-right:1px solid #ddd;} +.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #ddd;} +.pull-1 {margin-left:-40px;} +.pull-2 {margin-left:-80px;} +.pull-3 {margin-left:-120px;} +.pull-4 {margin-left:-160px;} +.pull-5 {margin-left:-200px;} +.pull-6 {margin-left:-240px;} +.pull-7 {margin-left:-280px;} +.pull-8 {margin-left:-320px;} +.pull-9 {margin-left:-360px;} +.pull-10 {margin-left:-400px;} +.pull-11 {margin-left:-440px;} +.pull-12 {margin-left:-480px;} +.pull-13 {margin-left:-520px;} +.pull-14 {margin-left:-560px;} +.pull-15 {margin-left:-600px;} +.pull-16 {margin-left:-640px;} +.pull-17 {margin-left:-680px;} +.pull-18 {margin-left:-720px;} +.pull-19 {margin-left:-760px;} +.pull-20 {margin-left:-800px;} +.pull-21 {margin-left:-840px;} +.pull-22 {margin-left:-880px;} +.pull-23 {margin-left:-920px;} +.pull-24 {margin-left:-960px;} +.pull-1, .pull-2, .pull-3, .pull-4, .pull-5, .pull-6, .pull-7, .pull-8, .pull-9, .pull-10, .pull-11, .pull-12, .pull-13, .pull-14, .pull-15, .pull-16, .pull-17, .pull-18, .pull-19, .pull-20, .pull-21, .pull-22, .pull-23, .pull-24 {float:left;position:relative;} +.push-1 {margin:0 -40px 1.5em 40px;} +.push-2 {margin:0 -80px 1.5em 80px;} +.push-3 {margin:0 -120px 1.5em 120px;} +.push-4 {margin:0 -160px 1.5em 160px;} +.push-5 {margin:0 -200px 1.5em 200px;} +.push-6 {margin:0 -240px 1.5em 240px;} +.push-7 {margin:0 -280px 1.5em 280px;} +.push-8 {margin:0 -320px 1.5em 320px;} +.push-9 {margin:0 -360px 1.5em 360px;} +.push-10 {margin:0 -400px 1.5em 400px;} +.push-11 {margin:0 -440px 1.5em 440px;} +.push-12 {margin:0 -480px 1.5em 480px;} +.push-13 {margin:0 -520px 1.5em 520px;} +.push-14 {margin:0 -560px 1.5em 560px;} +.push-15 {margin:0 -600px 1.5em 600px;} +.push-16 {margin:0 -640px 1.5em 640px;} +.push-17 {margin:0 -680px 1.5em 680px;} +.push-18 {margin:0 -720px 1.5em 720px;} +.push-19 {margin:0 -760px 1.5em 760px;} +.push-20 {margin:0 -800px 1.5em 800px;} +.push-21 {margin:0 -840px 1.5em 840px;} +.push-22 {margin:0 -880px 1.5em 880px;} +.push-23 {margin:0 -920px 1.5em 920px;} +.push-24 {margin:0 -960px 1.5em 960px;} +.push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:left;position:relative;} +div.prepend-top, .prepend-top {margin-top:1.5em;} +div.append-bottom, .append-bottom {margin-bottom:1.5em;} +.box {padding:1.5em;margin-bottom:1.5em;background:#e5eCf9;} +hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:1px;margin:0 0 17px;border:none;} +hr.space {background:#fff;color:#fff;visibility:hidden;} +.clearfix:after, .container:after {content:"\0020";display:block;height:0;clear:both;visibility:hidden;overflow:hidden;} +.clearfix, .container {display:block;} +.clear {clear:both;} diff --git a/testdrive/index-test.php b/testdrive/index-test.php new file mode 100644 index 0000000000..c6d5a0464b --- /dev/null +++ b/testdrive/index-test.php @@ -0,0 +1,15 @@ +run(); diff --git a/testdrive/index.php b/testdrive/index.php new file mode 100644 index 0000000000..11332f3fe8 --- /dev/null +++ b/testdrive/index.php @@ -0,0 +1,13 @@ +run(); diff --git a/testdrive/protected/.htaccess b/testdrive/protected/.htaccess new file mode 100644 index 0000000000..8d2f25636d --- /dev/null +++ b/testdrive/protected/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/testdrive/protected/components/Controller.php b/testdrive/protected/components/Controller.php new file mode 100644 index 0000000000..4d278623f6 --- /dev/null +++ b/testdrive/protected/components/Controller.php @@ -0,0 +1,23 @@ + password + 'demo'=>'demo', + 'admin'=>'admin', + ); + if(!isset($users[$this->username])) + $this->errorCode=self::ERROR_USERNAME_INVALID; + elseif($users[$this->username]!==$this->password) + $this->errorCode=self::ERROR_PASSWORD_INVALID; + else + $this->errorCode=self::ERROR_NONE; + return !$this->errorCode; + } +} \ No newline at end of file diff --git a/testdrive/protected/config/console.php b/testdrive/protected/config/console.php new file mode 100644 index 0000000000..dd3b3bc5b6 --- /dev/null +++ b/testdrive/protected/config/console.php @@ -0,0 +1,29 @@ +dirname(__FILE__).DIRECTORY_SEPARATOR.'..', + 'name'=>'My Console Application', + + // preloading 'log' component + 'preload'=>array('log'), + + // application components + 'components'=>array( + + // database settings are configured in database.php + 'db'=>require(dirname(__FILE__).'/database.php'), + + 'log'=>array( + 'class'=>'CLogRouter', + 'routes'=>array( + array( + 'class'=>'CFileLogRoute', + 'levels'=>'error, warning', + ), + ), + ), + + ), +); diff --git a/testdrive/protected/config/database.php b/testdrive/protected/config/database.php new file mode 100644 index 0000000000..02f9aadc29 --- /dev/null +++ b/testdrive/protected/config/database.php @@ -0,0 +1,14 @@ + 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db', + // uncomment the following lines to use a MySQL database + /* + 'connectionString' => 'mysql:host=localhost;dbname=testdrive', + 'emulatePrepare' => true, + 'username' => 'root', + 'password' => '', + 'charset' => 'utf8', + */ +); \ No newline at end of file diff --git a/testdrive/protected/config/main.php b/testdrive/protected/config/main.php new file mode 100644 index 0000000000..777f285ad9 --- /dev/null +++ b/testdrive/protected/config/main.php @@ -0,0 +1,85 @@ +dirname(__FILE__).DIRECTORY_SEPARATOR.'..', + 'name'=>'My Web Application', + + // preloading 'log' component + 'preload'=>array('log'), + + // autoloading model and component classes + 'import'=>array( + 'application.models.*', + 'application.components.*', + ), + + 'modules'=>array( + // uncomment the following to enable the Gii tool + /* + 'gii'=>array( + 'class'=>'system.gii.GiiModule', + 'password'=>'Enter Your Password Here', + // If removed, Gii defaults to localhost only. Edit carefully to taste. + 'ipFilters'=>array('127.0.0.1','::1'), + ), + */ + ), + + // application components + 'components'=>array( + + 'user'=>array( + // enable cookie-based authentication + 'allowAutoLogin'=>true, + ), + + // uncomment the following to enable URLs in path-format + /* + 'urlManager'=>array( + 'urlFormat'=>'path', + 'rules'=>array( + '/'=>'/view', + '//'=>'/', + '/'=>'/', + ), + ), + */ + + // database settings are configured in database.php + 'db'=>require(dirname(__FILE__).'/database.php'), + + 'errorHandler'=>array( + // use 'site/error' action to display errors + 'errorAction'=>YII_DEBUG ? null : 'site/error', + ), + + 'log'=>array( + 'class'=>'CLogRouter', + 'routes'=>array( + array( + 'class'=>'CFileLogRoute', + 'levels'=>'error, warning', + ), + // uncomment the following to show log messages on web pages + /* + array( + 'class'=>'CWebLogRoute', + ), + */ + ), + ), + + ), + + // application-level parameters that can be accessed + // using Yii::app()->params['paramName'] + 'params'=>array( + // this is used in contact page + 'adminEmail'=>'webmaster@example.com', + ), +); diff --git a/testdrive/protected/config/test.php b/testdrive/protected/config/test.php new file mode 100644 index 0000000000..fd7085a0d2 --- /dev/null +++ b/testdrive/protected/config/test.php @@ -0,0 +1,17 @@ +array( + 'fixture'=>array( + 'class'=>'system.test.CDbFixtureManager', + ), + /* uncomment the following to provide test database connection + 'db'=>array( + 'connectionString'=>'DSN for test database', + ), + */ + ), + ) +); diff --git a/testdrive/protected/controllers/SiteController.php b/testdrive/protected/controllers/SiteController.php new file mode 100644 index 0000000000..a6a790e22c --- /dev/null +++ b/testdrive/protected/controllers/SiteController.php @@ -0,0 +1,109 @@ +array( + 'class'=>'CCaptchaAction', + 'backColor'=>0xFFFFFF, + ), + // page action renders "static" pages stored under 'protected/views/site/pages' + // They can be accessed via: index.php?r=site/page&view=FileName + 'page'=>array( + 'class'=>'CViewAction', + ), + ); + } + + /** + * This is the default 'index' action that is invoked + * when an action is not explicitly requested by users. + */ + public function actionIndex() + { + // renders the view file 'protected/views/site/index.php' + // using the default layout 'protected/views/layouts/main.php' + $this->render('index'); + } + + /** + * This is the action to handle external exceptions. + */ + public function actionError() + { + if($error=Yii::app()->errorHandler->error) + { + if(Yii::app()->request->isAjaxRequest) + echo $error['message']; + else + $this->render('error', $error); + } + } + + /** + * Displays the contact page + */ + public function actionContact() + { + $model=new ContactForm; + if(isset($_POST['ContactForm'])) + { + $model->attributes=$_POST['ContactForm']; + if($model->validate()) + { + $name='=?UTF-8?B?'.base64_encode($model->name).'?='; + $subject='=?UTF-8?B?'.base64_encode($model->subject).'?='; + $headers="From: $name <{$model->email}>\r\n". + "Reply-To: {$model->email}\r\n". + "MIME-Version: 1.0\r\n". + "Content-Type: text/plain; charset=UTF-8"; + + mail(Yii::app()->params['adminEmail'],$subject,$model->body,$headers); + Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.'); + $this->refresh(); + } + } + $this->render('contact',array('model'=>$model)); + } + + /** + * Displays the login page + */ + public function actionLogin() + { + $model=new LoginForm; + + // if it is ajax validation request + if(isset($_POST['ajax']) && $_POST['ajax']==='login-form') + { + echo CActiveForm::validate($model); + Yii::app()->end(); + } + + // collect user input data + if(isset($_POST['LoginForm'])) + { + $model->attributes=$_POST['LoginForm']; + // validate user input and redirect to the previous page if valid + if($model->validate() && $model->login()) + $this->redirect(Yii::app()->user->returnUrl); + } + // display the login form + $this->render('login',array('model'=>$model)); + } + + /** + * Logs out the current user and redirect to homepage. + */ + public function actionLogout() + { + Yii::app()->user->logout(); + $this->redirect(Yii::app()->homeUrl); + } +} \ No newline at end of file diff --git a/testdrive/protected/data/schema.mysql.sql b/testdrive/protected/data/schema.mysql.sql new file mode 100644 index 0000000000..32788bdab5 --- /dev/null +++ b/testdrive/protected/data/schema.mysql.sql @@ -0,0 +1,28 @@ +CREATE TABLE tbl_user ( + id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(128) NOT NULL, + password VARCHAR(128) NOT NULL, + email VARCHAR(128) NOT NULL +); + +INSERT INTO tbl_user (username, password, email) VALUES ('test1', 'pass1', 'test1@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test2', 'pass2', 'test2@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test3', 'pass3', 'test3@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test4', 'pass4', 'test4@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test5', 'pass5', 'test5@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test6', 'pass6', 'test6@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test7', 'pass7', 'test7@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test8', 'pass8', 'test8@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test9', 'pass9', 'test9@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test10', 'pass10', 'test10@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test11', 'pass11', 'test11@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test12', 'pass12', 'test12@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test13', 'pass13', 'test13@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test14', 'pass14', 'test14@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test15', 'pass15', 'test15@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test16', 'pass16', 'test16@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test17', 'pass17', 'test17@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test18', 'pass18', 'test18@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test19', 'pass19', 'test19@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test20', 'pass20', 'test20@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test21', 'pass21', 'test21@example.com'); diff --git a/testdrive/protected/data/schema.sqlite.sql b/testdrive/protected/data/schema.sqlite.sql new file mode 100644 index 0000000000..e5e083015b --- /dev/null +++ b/testdrive/protected/data/schema.sqlite.sql @@ -0,0 +1,28 @@ +CREATE TABLE tbl_user ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + username VARCHAR(128) NOT NULL, + password VARCHAR(128) NOT NULL, + email VARCHAR(128) NOT NULL +); + +INSERT INTO tbl_user (username, password, email) VALUES ('test1', 'pass1', 'test1@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test2', 'pass2', 'test2@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test3', 'pass3', 'test3@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test4', 'pass4', 'test4@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test5', 'pass5', 'test5@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test6', 'pass6', 'test6@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test7', 'pass7', 'test7@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test8', 'pass8', 'test8@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test9', 'pass9', 'test9@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test10', 'pass10', 'test10@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test11', 'pass11', 'test11@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test12', 'pass12', 'test12@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test13', 'pass13', 'test13@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test14', 'pass14', 'test14@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test15', 'pass15', 'test15@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test16', 'pass16', 'test16@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test17', 'pass17', 'test17@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test18', 'pass18', 'test18@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test19', 'pass19', 'test19@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test20', 'pass20', 'test20@example.com'); +INSERT INTO tbl_user (username, password, email) VALUES ('test21', 'pass21', 'test21@example.com'); diff --git a/testdrive/protected/data/testdrive.db b/testdrive/protected/data/testdrive.db new file mode 100644 index 0000000000..0672b2190b Binary files /dev/null and b/testdrive/protected/data/testdrive.db differ diff --git a/testdrive/protected/models/ContactForm.php b/testdrive/protected/models/ContactForm.php new file mode 100644 index 0000000000..86541cb981 --- /dev/null +++ b/testdrive/protected/models/ContactForm.php @@ -0,0 +1,42 @@ +!CCaptcha::checkRequirements()), + ); + } + + /** + * Declares customized attribute labels. + * If not declared here, an attribute would have a label that is + * the same as its name with the first letter in upper case. + */ + public function attributeLabels() + { + return array( + 'verifyCode'=>'Verification Code', + ); + } +} \ No newline at end of file diff --git a/testdrive/protected/models/LoginForm.php b/testdrive/protected/models/LoginForm.php new file mode 100644 index 0000000000..632c475780 --- /dev/null +++ b/testdrive/protected/models/LoginForm.php @@ -0,0 +1,79 @@ +'Remember me next time', + ); + } + + /** + * Authenticates the password. + * This is the 'authenticate' validator as declared in rules(). + * @param string $attribute the name of the attribute to be validated. + * @param array $params additional parameters passed with rule when being executed. + */ + public function authenticate($attribute,$params) + { + if(!$this->hasErrors()) + { + $this->_identity=new UserIdentity($this->username,$this->password); + if(!$this->_identity->authenticate()) + $this->addError('password','Incorrect username or password.'); + } + } + + /** + * Logs in the user using the given username and password in the model. + * @return boolean whether login is successful + */ + public function login() + { + if($this->_identity===null) + { + $this->_identity=new UserIdentity($this->username,$this->password); + $this->_identity->authenticate(); + } + if($this->_identity->errorCode===UserIdentity::ERROR_NONE) + { + $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days + Yii::app()->user->login($this->_identity,$duration); + return true; + } + else + return false; + } +} diff --git a/testdrive/protected/tests/WebTestCase.php b/testdrive/protected/tests/WebTestCase.php new file mode 100644 index 0000000000..d252bba2d9 --- /dev/null +++ b/testdrive/protected/tests/WebTestCase.php @@ -0,0 +1,25 @@ +setBrowserUrl(TEST_BASE_URL); + } +} diff --git a/testdrive/protected/tests/bootstrap.php b/testdrive/protected/tests/bootstrap.php new file mode 100644 index 0000000000..4404cac965 --- /dev/null +++ b/testdrive/protected/tests/bootstrap.php @@ -0,0 +1,10 @@ +open(''); + $this->assertTextPresent('Welcome'); + } + + public function testContact() + { + $this->open('?r=site/contact'); + $this->assertTextPresent('Contact Us'); + $this->assertElementPresent('name=ContactForm[name]'); + + $this->type('name=ContactForm[name]','tester'); + $this->type('name=ContactForm[email]','tester@example.com'); + $this->type('name=ContactForm[subject]','test subject'); + $this->click("//input[@value='Submit']"); + $this->waitForTextPresent('Body cannot be blank.'); + } + + public function testLoginLogout() + { + $this->open(''); + // ensure the user is logged out + if($this->isTextPresent('Logout')) + $this->clickAndWait('link=Logout (demo)'); + + // test login process, including validation + $this->clickAndWait('link=Login'); + $this->assertElementPresent('name=LoginForm[username]'); + $this->type('name=LoginForm[username]','demo'); + $this->click("//input[@value='Login']"); + $this->waitForTextPresent('Password cannot be blank.'); + $this->type('name=LoginForm[password]','demo'); + $this->clickAndWait("//input[@value='Login']"); + $this->assertTextNotPresent('Password cannot be blank.'); + $this->assertTextPresent('Logout'); + + // test logout process + $this->assertTextNotPresent('Login'); + $this->clickAndWait('link=Logout (demo)'); + $this->assertTextPresent('Login'); + } +} diff --git a/testdrive/protected/tests/phpunit.xml b/testdrive/protected/tests/phpunit.xml new file mode 100644 index 0000000000..22c96ffd41 --- /dev/null +++ b/testdrive/protected/tests/phpunit.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/testdrive/protected/views/layouts/column1.php b/testdrive/protected/views/layouts/column1.php new file mode 100644 index 0000000000..702fd65979 --- /dev/null +++ b/testdrive/protected/views/layouts/column1.php @@ -0,0 +1,6 @@ + +beginContent('//layouts/main'); ?> +
+ +
+endContent(); ?> \ No newline at end of file diff --git a/testdrive/protected/views/layouts/column2.php b/testdrive/protected/views/layouts/column2.php new file mode 100644 index 0000000000..b588bf69ee --- /dev/null +++ b/testdrive/protected/views/layouts/column2.php @@ -0,0 +1,22 @@ + +beginContent('//layouts/main'); ?> +
+
+ +
+
+
+ +
+endContent(); ?> \ No newline at end of file diff --git a/testdrive/protected/views/layouts/main.php b/testdrive/protected/views/layouts/main.php new file mode 100644 index 0000000000..a8533aea93 --- /dev/null +++ b/testdrive/protected/views/layouts/main.php @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + <?php echo CHtml::encode($this->pageTitle); ?> + + + + +
+ + + + + breadcrumbs)):?> + widget('zii.widgets.CBreadcrumbs', array( + 'links'=>$this->breadcrumbs, + )); ?> + + + + +
+ + + +
+ + + diff --git a/testdrive/protected/views/site/contact.php b/testdrive/protected/views/site/contact.php new file mode 100644 index 0000000000..baad25e048 --- /dev/null +++ b/testdrive/protected/views/site/contact.php @@ -0,0 +1,85 @@ +pageTitle=Yii::app()->name . ' - Contact Us'; +$this->breadcrumbs=array( + 'Contact', +); +?> + +

Contact Us

+ +user->hasFlash('contact')): ?> + +
+ user->getFlash('contact'); ?> +
+ + + +

+If you have business inquiries or other questions, please fill out the following form to contact us. Thank you. +

+ +
+ +beginWidget('CActiveForm', array( + 'id'=>'contact-form', + 'enableClientValidation'=>true, + 'clientOptions'=>array( + 'validateOnSubmit'=>true, + ), +)); ?> + +

Fields with * are required.

+ + errorSummary($model); ?> + +
+ labelEx($model,'name'); ?> + textField($model,'name'); ?> + error($model,'name'); ?> +
+ +
+ labelEx($model,'email'); ?> + textField($model,'email'); ?> + error($model,'email'); ?> +
+ +
+ labelEx($model,'subject'); ?> + textField($model,'subject',array('size'=>60,'maxlength'=>128)); ?> + error($model,'subject'); ?> +
+ +
+ labelEx($model,'body'); ?> + textArea($model,'body',array('rows'=>6, 'cols'=>50)); ?> + error($model,'body'); ?> +
+ + +
+ labelEx($model,'verifyCode'); ?> +
+ widget('CCaptcha'); ?> + textField($model,'verifyCode'); ?> +
+
Please enter the letters as they are shown in the image above. +
Letters are not case-sensitive.
+ error($model,'verifyCode'); ?> +
+ + +
+ +
+ +endWidget(); ?> + +
+ + \ No newline at end of file diff --git a/testdrive/protected/views/site/error.php b/testdrive/protected/views/site/error.php new file mode 100644 index 0000000000..d0dcb8084e --- /dev/null +++ b/testdrive/protected/views/site/error.php @@ -0,0 +1,15 @@ +pageTitle=Yii::app()->name . ' - Error'; +$this->breadcrumbs=array( + 'Error', +); +?> + +

Error

+ +
+ +
\ No newline at end of file diff --git a/testdrive/protected/views/site/index.php b/testdrive/protected/views/site/index.php new file mode 100644 index 0000000000..4158cf048a --- /dev/null +++ b/testdrive/protected/views/site/index.php @@ -0,0 +1,20 @@ +pageTitle=Yii::app()->name; +?> + +

Welcome to name); ?>

+ +

Congratulations! You have successfully created your Yii application.

+ +

You may change the content of this page by modifying the following two files:

+
    +
  • View file:
  • +
  • Layout file: getLayoutFile('main'); ?>
  • +
+ +

For more details on how to further develop this application, please read +the documentation. +Feel free to ask in the forum, +should you have any questions.

diff --git a/testdrive/protected/views/site/login.php b/testdrive/protected/views/site/login.php new file mode 100644 index 0000000000..3c16748c4f --- /dev/null +++ b/testdrive/protected/views/site/login.php @@ -0,0 +1,53 @@ +pageTitle=Yii::app()->name . ' - Login'; +$this->breadcrumbs=array( + 'Login', +); +?> + +

Login

+ +

Please fill out the following form with your login credentials:

+ +
+beginWidget('CActiveForm', array( + 'id'=>'login-form', + 'enableClientValidation'=>true, + 'clientOptions'=>array( + 'validateOnSubmit'=>true, + ), +)); ?> + +

Fields with * are required.

+ +
+ labelEx($model,'username'); ?> + textField($model,'username'); ?> + error($model,'username'); ?> +
+ +
+ labelEx($model,'password'); ?> + passwordField($model,'password'); ?> + error($model,'password'); ?> +

+ Hint: You may login with demo/demo or admin/admin. +

+
+ +
+ checkBox($model,'rememberMe'); ?> + label($model,'rememberMe'); ?> + error($model,'rememberMe'); ?> +
+ +
+ +
+ +endWidget(); ?> +
diff --git a/testdrive/protected/views/site/pages/about.php b/testdrive/protected/views/site/pages/about.php new file mode 100644 index 0000000000..d8aa3c579a --- /dev/null +++ b/testdrive/protected/views/site/pages/about.php @@ -0,0 +1,12 @@ +pageTitle=Yii::app()->name . ' - About'; +$this->breadcrumbs=array( + 'About', +); +?> +

About

+ +

This is a "static" page. You may change the content of this page +by updating the file .

diff --git a/testdrive/protected/yiic b/testdrive/protected/yiic new file mode 100644 index 0000000000..7f56f54f86 --- /dev/null +++ b/testdrive/protected/yiic @@ -0,0 +1,4 @@ +#!/usr/bin/env php +