Skip to content

Commit

Permalink
Merge pull request #751 from nextcloud/release-1.0.0
Browse files Browse the repository at this point in the history
Release 1.0.0
  • Loading branch information
v1r0x committed Jan 19, 2020
2 parents 11957d1 + 5b08fae commit c74ca32
Show file tree
Hide file tree
Showing 24 changed files with 163 additions and 66 deletions.
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ lint-fix:
.PHONY: clean
clean:
rm -rf $(build_dir)
rm -f js/polls.js
rm -f js/polls.js.map

rm -rf js/
mkdir -p js
clean-dev: clean
rm -rf node_modules
rm -rf ./vendor
Expand Down
26 changes: 11 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/nextcloud/polls.svg?style=flat-square)](https://scrutinizer-ci.com/g/nextcloud/polls)
[![Software License](https://img.shields.io/badge/license-AGPL-brightgreen.svg?style=flat-square)](LICENSE)

## This branch is in alpha state, do not use for production needs

This is a poll app, similar to doodle or dudle, for Nextcloud written in PHP and JS / Vue.
It is a rework of the already existing [polls app](https://github.com/raduvatav/polls) written by @raduvatav.

**Note**: ownCloud is **no longer** supported! Last (confirmed) working version is 0.8.1 and is released in the oC marketplace.
**Note**: IE11 users will face some CSS problems (see #541). Please change to a compatible browser (Firefox, Chrome, Edge, etc.). Or better: don't even try this browser

### Features
- :bar_chart: Create / edit polls (datetimes _and_ texts)
- :bar_chart: Create / edit polls (datetimes and texts)
- :date: Set expiration date
- :lock: Restrict access (only logged in users, certain groups / users, hidden and public)
- :lock: Restrict access (all site users or invited users only)
- :speech_balloon: Comments

### Bugs
Expand All @@ -27,23 +24,22 @@ Create a new poll from the navigation bar and get an overview of your polls
![Overview](screenshots/overview.png)

Vote and comment
![Vote](screenshots/vote.png)
![Vote](screenshots/comment.png)

Edit poll on the vote page as owner or an admin
![Edit poll](screenshots/edit-poll.png)
![Edit options](screenshots/edit-options.png)
Edit poll on the vote page
![Edit poll](screenshots/configurations.png)
![Edit options](screenshots/options.png)

Add shared links to your poll
![Share poll](screenshots/edit-shares.png)
![Share poll](screenshots/shares.png)

View the vote page on mobiles
![Vote mobile portrait](screenshots/vote-mobile-portrait.png)
View the vote page on mobiles (Turn phone to landscape to see th full table)
![Vote mobile portrait](screenshots/mobile-portrait.png)

Turn phone to landscape to see details
![Vote mobile landscape](screenshots/vote-mobile-landscape.png)
Only the owner can edit the poll. Granting access to admin users will be available in the next version.

## Installation / Update
This app is supposed to work on Nextcloud version 13+.
This app is supposed to work on Nextcloud version 16+.

### Install latest release
You can download and install the latest release from the [Nextcloud app store](https://apps.nextcloud.com/apps/polls).
Expand Down
21 changes: 14 additions & 7 deletions lib/Migration/Version0010Date20191227063812.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,13 @@ public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

if ($schema->hasTable('polls_polls')) {
if ($schema->hasTable('polls_polls') &&
$schema->hasTable('polls_events')) {
$this->migrateEvents();
}

if ($schema->hasTable('polls_share')) {
if ($schema->hasTable('polls_share') &&
$schema->hasTable('polls_events')) {
$this->copyTokens();
}
}
Expand Down Expand Up @@ -343,7 +345,8 @@ protected function copyTokens() {
'type' => $insert->createParameter('type'),
'poll_id' => $insert->createParameter('poll_id'),
'user_id' => $insert->createParameter('user_id'),
'user_email' => $insert->createParameter('user_email')
'user_email' => $insert->createParameter('user_email'),
'user' => $insert->createParameter('user')
]);
$query = $this->connection->getQueryBuilder();
$query->select('*')
Expand All @@ -358,7 +361,8 @@ protected function copyTokens() {
->setParameter('type', 'public')
->setParameter('poll_id', $row['id'])
->setParameter('user_id', null)
->setParameter('user_email', null);
->setParameter('user_email', null)
->setParameter('user', '');
$insert->execute();
} elseif ($row['access'] == 'hidden') {
// copy the hash to a public share
Expand All @@ -368,7 +372,8 @@ protected function copyTokens() {
->setParameter('type', 'public')
->setParameter('poll_id', $row['id'])
->setParameter('user_id', null)
->setParameter('user_email', null);
->setParameter('user_email', null)
->setParameter('user', '');
$insert->execute();
} elseif ($row['access'] == 'registered') {
// copy the hash to a public share
Expand All @@ -378,7 +383,8 @@ protected function copyTokens() {
->setParameter('type', 'public')
->setParameter('poll_id', $row['id'])
->setParameter('user_id', null)
->setParameter('user_email', null);
->setParameter('user_email', null)
->setParameter('user', '');
} else {
// create a personal share for invitated users

Expand All @@ -398,7 +404,8 @@ protected function copyTokens() {
->setParameter('type', $parts[0])
->setParameter('poll_id', $row['id'])
->setParameter('user_id', $parts[1])
->setParameter('user_email', null);
->setParameter('user_email', null)
->setParameter('user', '');
$insert->execute();
}
}
Expand Down
73 changes: 73 additions & 0 deletions lib/Migration/Version0010Date20200119101800.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/**
* @copyright Copyright (c) 2017 René Gieling <[email protected]>
*
* @author René Gieling <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\Polls\Migration;

use OCP\DB\ISchemaWrapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IConfig;
use OCP\IDBConnection;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;

/**
* Installation class for the polls app.
* Initial db creation
*/
class Version0010Date20200119101800 extends SimpleMigrationStep {

/** @var IDBConnection */
protected $connection;

/** @var IConfig */
protected $config;

/**
* @param IDBConnection $connection
* @param IConfig $config
*/
public function __construct(IDBConnection $connection, IConfig $config) {
$this->connection = $connection;
$this->config = $config;
}

/**
* @param IOutput $output
* @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
* @since 13.0.0
*/
public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

if ($schema->hasTable('polls_polls') &&
$schema->hasTable('polls_events')) {

$schema->dropTable('polls_events');
}

return $schema;
}
}
Binary file added screenshots/comment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/configuration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screenshots/edit-options.png
Binary file not shown.
Binary file removed screenshots/edit-poll.png
Binary file not shown.
Binary file removed screenshots/edit-shares.png
Binary file not shown.
Binary file added screenshots/mobile-portrait.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/options.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/shares.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed screenshots/vote-mobile-landscape.png
Binary file not shown.
Binary file removed screenshots/vote-mobile-portrait.png
Binary file not shown.
Binary file removed screenshots/vote.png
Binary file not shown.
7 changes: 6 additions & 1 deletion src/js/components/Base/PollInformation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<template>
<div class="poll-information">
<UserBubble :user="poll.owner" :display-name="poll.owner" />
{{ t('polls', ' started this poll on %n. ', 1, moment.unix(poll.created).format('LLLL')) }}
{{ t('polls', 'started this poll on %n. ', 1, moment.unix(poll.created).format('LLLL')) }}
<span v-if="expired">{{ t('polls', 'Voting is no more possible, because this poll expired since %n.', 1, moment.unix(poll.expire).format('LLLL')) }}</span>
<span v-if="!expired && poll.expire && acl.allowVote">{{ t('polls', 'You can place your vote until %n. ', 1, moment.unix(poll.expire).format('LLLL')) }}</span>
<span v-if="poll.anonymous">{{ t('polls', 'The names of other participants are hidden, as this is an anonymous poll. ') }}</span>
Expand All @@ -33,10 +33,15 @@

<script>
import { mapState, mapGetters } from 'vuex'
import { UserBubble } from '@nextcloud/vue'
export default {
name: 'PollInformation',
components: {
UserBubble
},
computed: {
...mapState({
acl: state => state.acl,
Expand Down
8 changes: 7 additions & 1 deletion src/js/components/PollList/PollListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<div class="toggleUserActions">
<div v-click-outside="hideMenu" class="icon-more" @click="toggleMenu" />
<div class="popovermenu" :class="{ 'open': openedMenu }">
<popover-menu :menu="menuItems" />
<PopoverMenu :menu="menuItems" />
</div>
</div>
</div>
Expand All @@ -87,9 +87,15 @@
</template>

<script>
import { PopoverMenu } from '@nextcloud/vue'
export default {
name: 'PollListItem',
components: {
PopoverMenu
},
props: {
header: {
type: Boolean,
Expand Down
32 changes: 17 additions & 15 deletions src/js/components/SideBar/SideBarTabConfiguration.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
type="checkbox" class="checkbox">
<label class="title" for="expiration"> {{ t('polls', 'Expires') }} </label>

<DatePicker v-show="pollExpiration"
<DatetimePicker v-show="pollExpiration"
v-model="pollExpire" v-bind="expirationDatePicker" style="width:170px" />
</div>

Expand All @@ -82,10 +82,15 @@
<script>
import debounce from 'lodash/debounce'
import { mapState, mapMutations, mapActions } from 'vuex'
import { DatetimePicker } from '@nextcloud/vue'
export default {
name: 'SideBarTabConfiguration',
components: {
DatetimePicker
},
data() {
return {
writingPoll: false,
Expand All @@ -101,6 +106,15 @@ export default {
acl: state => state.acl
}),
firstDOW() {
// vue2-datepicker needs 7 for sunday
if (moment.localeData()._week.dow === 0) {
return 7
} else {
return moment.localeData()._week.dow
}
},
// Add bindings
pollDescription: {
get() {
Expand Down Expand Up @@ -183,18 +197,6 @@ export default {
}
},
langPicker() {
return {
formatLocale: {
months: moment.months(),
monthsShort: moment.monthsShort(),
weekdays: moment.weekdays(),
weekdaysMin: moment.weekdaysMin(),
firstDayOfWeek: moment.localeData()._week.dow
}
}
},
expirationDatePicker() {
return {
editable: true,
Expand All @@ -204,12 +206,12 @@ export default {
// TODO: use this for version 2.x
lang: OC.getLanguage().split('-')[0],
firstDayOfWeek: moment.localeData()._week.dow,
firstDayOfWeek: this.firstDOW,
// TODO: use this from version 3.x on
// lang: {
// formatLocale: {
// firstDayOfWeek: moment.localeData()._week.dow,
// firstDayOfWeek: this.firstDOW,
// months: moment.months(),
// monthsShort: moment.monthsShort(),
// weekdays: moment.weekdays(),
Expand Down
20 changes: 15 additions & 5 deletions src/js/components/SideBar/SideBarTabDateOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<label class="title icon-calendar">
{{ t('polls', 'Add a date option') }}
</label>
<DatePicker v-model="lastOption"
<DatetimePicker v-model="lastOption"
v-bind="optionDatePicker"
style="width:100%"
confirm
Expand Down Expand Up @@ -63,7 +63,7 @@
</template>

<script>
import { Multiselect } from '@nextcloud/vue'
import { DatetimePicker, Multiselect } from '@nextcloud/vue'
import { mapGetters, mapState } from 'vuex'
import DatePollItem from '../Base/DatePollItem'
Expand All @@ -72,7 +72,8 @@ export default {
components: {
Multiselect,
DatePollItem
DatePollItem,
DatetimePicker
},
data() {
Expand All @@ -93,6 +94,15 @@ export default {
...mapGetters(['sortedOptions']),
firstDOW() {
// vue2-datepicker needs 7 for sunday
if (moment.localeData()._week.dow === 0) {
return 7
} else {
return moment.localeData()._week.dow
}
},
optionDatePicker() {
return {
editable: false,
Expand All @@ -102,12 +112,12 @@ export default {
// TODO: use this for version 2.x
lang: OC.getLanguage().split('-')[0],
firstDayOfWeek: moment.localeData()._week.dow,
firstDayOfWeek: this.firstDOW,
// TODO: use this from version 3.x on
// lang: {
// formatLocale: {
// firstDayOfWeek: moment.localeData()._week.dow,
// firstDayOfWeek: this.firstDOW,
// months: moment.months(),
// monthsShort: moment.monthsShort(),
// weekdays: moment.weekdays(),
Expand Down
Loading

0 comments on commit c74ca32

Please sign in to comment.