diff --git a/lib/Command/Db/Rebuild.php b/lib/Command/Db/Rebuild.php
index f6dae27155..d8448a1461 100644
--- a/lib/Command/Db/Rebuild.php
+++ b/lib/Command/Db/Rebuild.php
@@ -56,6 +56,7 @@ protected function runCommands(): int {
$this->printComment('Step 2. Tidy records before rebuilding the schema');
$this->fixNullish();
+ $this->migrateShareLabels();
$this->printComment('Step 3. Create or update tables to current shema');
$this->createOrUpdateSchema();
@@ -101,6 +102,12 @@ private function fixNullish(): void {
$this->printInfo($messages, ' ');
}
+ private function migrateShareLabels(): void {
+ $this->printComment(' - migrate share labels to displayname for public shares');
+ $messages = $this->tableManager->migrateShareLabels();
+ $this->printInfo($messages, ' ');
+ }
+
/**
* Create index for $table
*/
diff --git a/lib/Db/Share.php b/lib/Db/Share.php
index c586371318..88ed289485 100644
--- a/lib/Db/Share.php
+++ b/lib/Db/Share.php
@@ -42,8 +42,6 @@
* @method ?int getAnonymizedVotes()
* @method int getDeleted()
* @method void setDeleted(int $value)
- * @method ?string getLabel()
- * @method void setLabel(?string $value)
*/
class Share extends EntityWithUser implements JsonSerializable {
/** @var string */
@@ -204,25 +202,32 @@ public function setPublicPollEmail(string $value): void {
}
/**
- * Share label for public shares, falls back to username until migrated
- * TODO: remove fallback after migration was introduced
+ * Share label for public shares, now stored as displayName
+ * TODO: remove after migration was introduced
+ */
+ public function setLabel(string $label): void {
+ $this->setDisplayName($label);
+ $this->label = $label;
+ }
+
+ /**
+ * Share label for public shares
+ * TODO: remove after migrating labels to displayName
*/
public function getLabel(): string {
- if ($this->getType() === self::TYPE_PUBLIC && $this->label) {
- return $this->label;
- }
- return $this->displayName ?? '';
+ // In case of public poll use label as fallback for displayName
+ return $this->displayName ?? $this->label ?? '';
}
/**
* Sharee's displayName. In case of public poll label is used instead
- * TODO: remove public poll chaeck after migration to label
+ * TODO: remove public poll check after migration labels to displayName
*/
public function getDisplayName(): string {
if ($this->getType() === self::TYPE_PUBLIC) {
- return '';
+ return $this->getLabel();
}
- return (string)$this->displayName;
+ return $this->displayName ?? '';
}
public function getTimeZoneName(): string {
diff --git a/lib/Db/V4/TableManager.php b/lib/Db/V4/TableManager.php
index a63c163927..4003694410 100644
--- a/lib/Db/V4/TableManager.php
+++ b/lib/Db/V4/TableManager.php
@@ -213,15 +213,17 @@ public function removeObsoleteColumns(): array {
foreach (TableSchema::GONE_COLUMNS as $tableName => $columns) {
$tableName = $this->dbPrefix . $tableName;
- if ($this->schema->hasTable($tableName)) {
- $table = $this->schema->getTable($tableName);
-
- foreach ($columns as $columnName) {
- if ($table->hasColumn($columnName)) {
- $dropped = true;
- $table->dropColumn($columnName);
- $messages[] = 'Dropped ' . $columnName . ' from ' . $tableName;
- }
+ if (!$this->schema->hasTable($tableName)) {
+ continue;
+ }
+
+ $table = $this->schema->getTable($tableName);
+
+ foreach ($columns as $columnName) {
+ if ($table->hasColumn($columnName)) {
+ $dropped = true;
+ $table->dropColumn($columnName);
+ $messages[] = 'Dropped ' . $columnName . ' from ' . $tableName;
}
}
}
@@ -375,33 +377,34 @@ private function deleteDuplicates(string $table, array $columns):int {
$this->needsSchema();
$qb = $this->connection->getQueryBuilder();
- if ($this->schema->hasTable($this->dbPrefix . $table)) {
- // identify duplicates
- $selection = $qb->selectDistinct('t1.id')
- ->from($table, 't1')
- ->innerJoin('t1', $table, 't2', $qb->expr()->lt('t1.id', 't2.id'));
+ if (!$this->schema->hasTable($this->dbPrefix . $table)) {
+ return 0;
+ }
- $i = 0;
+ // identify duplicates
+ $selection = $qb->selectDistinct('t1.id')
+ ->from($table, 't1')
+ ->innerJoin('t1', $table, 't2', $qb->expr()->lt('t1.id', 't2.id'));
- foreach ($columns as $column) {
- if ($i > 0) {
- $selection->andWhere($qb->expr()->eq('t1.' . $column, 't2.' . $column));
- } else {
- $selection->where($qb->expr()->eq('t1.' . $column, 't2.' . $column));
- }
- $i++;
+ $i = 0;
+
+ foreach ($columns as $column) {
+ if ($i > 0) {
+ $selection->andWhere($qb->expr()->eq('t1.' . $column, 't2.' . $column));
+ } else {
+ $selection->where($qb->expr()->eq('t1.' . $column, 't2.' . $column));
}
+ $i++;
+ }
- $duplicates = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN);
+ $duplicates = $qb->executeQuery()->fetchAll(PDO::FETCH_COLUMN);
- $this->connection->getQueryBuilder()
- ->delete($table)
- ->where('id in (:ids)')
- ->setParameter('ids', $duplicates, IQueryBuilder::PARAM_INT_ARRAY)
- ->executeStatement();
- return count($duplicates);
- }
- return 0;
+ $this->connection->getQueryBuilder()
+ ->delete($table)
+ ->where('id in (:ids)')
+ ->setParameter('ids', $duplicates, IQueryBuilder::PARAM_INT_ARRAY)
+ ->executeStatement();
+ return count($duplicates);
}
/**
@@ -423,19 +426,24 @@ public function removeObsoleteMigrations(): array {
}
public function fixVotes(): void {
- if ($this->schema->hasTable($this->dbPrefix . OptionMapper::TABLE)) {
- $table = $this->schema->getTable($this->dbPrefix . OptionMapper::TABLE);
- if ($table->hasColumn('duration')) {
- $foundOptions = $this->optionMapper->findOptionsWithDuration();
- foreach ($foundOptions as $option) {
- $this->voteMapper->fixVoteOptionText(
- $option->getPollId(),
- $option->getId(),
- $option->getPollOptionTextStart(),
- $option->getPollOptionText(),
- );
- }
- }
+ if (!$this->schema->hasTable($this->dbPrefix . OptionMapper::TABLE)) {
+ return;
+ }
+
+ $table = $this->schema->getTable($this->dbPrefix . OptionMapper::TABLE);
+
+ if (!$table->hasColumn('duration')) {
+ return;
+ }
+
+ $foundOptions = $this->optionMapper->findOptionsWithDuration();
+ foreach ($foundOptions as $option) {
+ $this->voteMapper->fixVoteOptionText(
+ $option->getPollId(),
+ $option->getId(),
+ $option->getPollOptionTextStart(),
+ $option->getPollOptionText(),
+ );
}
}
@@ -548,58 +556,64 @@ public function setLastInteraction(?int $timestamp = null): string {
*/
private function updateVoteHashes(Schema &$schema): array {
$messages = [];
- if ($schema->hasTable($this->dbPrefix . VoteMapper::TABLE)) {
- $table = $schema->getTable($this->dbPrefix . VoteMapper::TABLE);
- $count = 0;
- $updated = 0;
- if ($table->hasColumn('vote_option_hash')) {
- foreach ($this->voteMapper->getAll(includeNull: true) as $vote) {
- try {
- // if the hash of the vote differs from calculated hash update the vote hash
- if ($vote->getVoteOptionHash() !== Hash::getOptionHash($vote->getPollId(), $vote->getVoteOptionText())) {
- $vote->setVoteOptionHash(Hash::getOptionHash($vote->getPollId(), $vote->getVoteOptionText()));
- $vote = $this->voteMapper->update($vote);
- $updated++;
- }
-
- $count++;
-
- } catch (Exception $e) {
- $messages[] = 'Skip hash update - Error updating option hash for voteId ' . $vote->getId();
- $this->logger->error('Error updating option hash for voteId {id}', [
- 'id' => $vote->getId(),
- 'message' => $e->getMessage()
- ]);
- }
- }
+ if (!$schema->hasTable($this->dbPrefix . VoteMapper::TABLE)) {
+ $this->logger->error('{db} is missing- aborted recalculating hashes', [
+ 'db' => $this->dbPrefix . VoteMapper::TABLE
+ ]);
+ $messages[] = 'Table ' . $this->dbPrefix . VoteMapper::TABLE . ' does not exist';
+ return $messages;
+ }
- if ($updated === 0) {
- $this->logger->info('Verified {count} vote hashes in {db}', [
- 'count' => $count,
- 'db' => $this->dbPrefix . VoteMapper::TABLE
- ]);
- $messages[] = 'No vote hashes to update';
+ $table = $schema->getTable($this->dbPrefix . VoteMapper::TABLE);
- } else {
- $this->logger->info('Updated {updated} hashes of {count} votes in {db}', [
- 'updated' => $updated,
- 'count' => $count,
- 'db' => $this->dbPrefix . VoteMapper::TABLE
- ]);
- $messages[] = 'Updated ' . $updated . ' vote hashes';
+ if (!$table->hasColumn('vote_option_hash')) {
+ $this->logger->error('{db} is missing column \'poll_option_hash\' - aborted recalculating hashes', [
+ 'db' => $this->dbPrefix . VoteMapper::TABLE
+ ]);
+ $messages[] = 'Column \'vote_option_hash\' does not exist in ' . $this->dbPrefix . VoteMapper::TABLE;
+ return $messages;
+ }
+
+ $count = 0;
+ $updated = 0;
+ foreach ($this->voteMapper->getAll(includeNull: true) as $vote) {
+ try {
+ // if the hash of the vote differs from calculated hash update the vote hash
+ if ($vote->getVoteOptionHash() !== Hash::getOptionHash($vote->getPollId(), $vote->getVoteOptionText())) {
+ $vote->setVoteOptionHash(Hash::getOptionHash($vote->getPollId(), $vote->getVoteOptionText()));
+ $vote = $this->voteMapper->update($vote);
+ $updated++;
}
- } else {
- $this->logger->error('{db} is missing column \'poll_option_hash\' - aborted recalculating hashes', [
- 'db' => $this->dbPrefix . VoteMapper::TABLE
+ $count++;
+
+ } catch (Exception $e) {
+ $messages[] = 'Skip hash update - Error updating option hash for voteId ' . $vote->getId();
+ $this->logger->error('Error updating option hash for voteId {id}', [
+ 'id' => $vote->getId(),
+ 'message' => $e->getMessage()
]);
}
+ }
+
+ if ($updated === 0) {
+ $this->logger->info('Verified {count} vote hashes in {db}', [
+ 'count' => $count,
+ 'db' => $this->dbPrefix . VoteMapper::TABLE
+ ]);
+ $messages[] = 'No vote hashes to update';
+
} else {
- $this->logger->error('{db} is missing- aborted recalculating hashes', [
+ $this->logger->info('Updated {updated} hashes of {count} votes in {db}', [
+ 'updated' => $updated,
+ 'count' => $count,
'db' => $this->dbPrefix . VoteMapper::TABLE
]);
+ $messages[] = 'Updated ' . $updated . ' vote hashes';
+
}
+
return $messages;
}
@@ -611,53 +625,56 @@ private function updateVoteHashes(Schema &$schema): array {
private function updateOptionHashes(Schema &$schema): array {
$messages = [];
- if ($schema->hasTable($this->dbPrefix . OptionMapper::TABLE)) {
- $table = $schema->getTable($this->dbPrefix . OptionMapper::TABLE);
- $count = 0;
- $updated = 0;
-
- if ($table->hasColumn('poll_option_hash')) {
- foreach ($this->optionMapper->getAll(includeNull: true) as $option) {
- try {
- // if the option's hash differs from $actualHash update the option
- if ($option->getPollOptionHash() !== Hash::getOptionHash($option->getPollId(), $option->getPollOptionText())) {
- $option->setPollOptionHash(Hash::getOptionHash($option->getPollId(), $option->getPollOptionText()));
- $option = $this->optionMapper->update($option);
- $updated++;
- }
-
- $count++;
-
- } catch (Exception $e) {
- $messages[] = 'Skip hash update - Error updating option hash for optionId ' . $option->getId();
- $this->logger->error('Error updating option hash for optionId {id}', ['id' => $option->getId(), 'message' => $e->getMessage()]);
- }
- }
+ if (!$schema->hasTable($this->dbPrefix . OptionMapper::TABLE)) {
+ $this->logger->error('{db} is missing - aborted recalculating hashes', [ 'db' => $this->dbPrefix . OptionMapper::TABLE]);
+ $messages[] = 'Table ' . $this->dbPrefix . OptionMapper::TABLE . ' does not exist';
+ return $messages;
+ }
+ $table = $schema->getTable($this->dbPrefix . OptionMapper::TABLE);
- if ($updated === 0) {
- $this->logger->info('Verified {count} option hashes in {db}', [
- 'count' => $count,
- 'db' => $this->dbPrefix . OptionMapper::TABLE
- ]);
- $messages[] = 'No option hashes to update';
+ if (!$table->hasColumn('poll_option_hash')) {
+ $this->logger->error('{db} is missing column \'poll_option_hash\' - aborted recalculating hashes', [ 'db' => $this->dbPrefix . OptionMapper::TABLE]);
+ $messages[] = 'Column \'poll_option_hash\' does not exist in ' . $this->dbPrefix . OptionMapper::TABLE;
+ return $messages;
+ }
- } else {
- $this->logger->info('Updated {updated} hashes of {count} options in {db}', [
- 'updated' => $updated,
- 'count' => $count,
- 'db' => $this->dbPrefix . OptionMapper::TABLE
- ]);
- $messages[] = 'Updated ' . $updated . ' option hashes';
+ $count = 0;
+ $updated = 0;
+ foreach ($this->optionMapper->getAll(includeNull: true) as $option) {
+ try {
+ // if the option's hash differs from $actualHash update the option
+ if ($option->getPollOptionHash() !== Hash::getOptionHash($option->getPollId(), $option->getPollOptionText())) {
+ $option->setPollOptionHash(Hash::getOptionHash($option->getPollId(), $option->getPollOptionText()));
+ $option = $this->optionMapper->update($option);
+ $updated++;
}
- } else {
- $this->logger->error('{db} is missing column \'poll_option_hash\' - aborted recalculating hashes', [ 'db' => $this->dbPrefix . OptionMapper::TABLE]);
+ $count++;
+
+ } catch (Exception $e) {
+ $messages[] = 'Skip hash update - Error updating option hash for optionId ' . $option->getId();
+ $this->logger->error('Error updating option hash for optionId {id}', ['id' => $option->getId(), 'message' => $e->getMessage()]);
}
+ }
+
+ if ($updated === 0) {
+ $this->logger->info('Verified {count} option hashes in {db}', [
+ 'count' => $count,
+ 'db' => $this->dbPrefix . OptionMapper::TABLE
+ ]);
+ $messages[] = 'No option hashes to update';
} else {
- $this->logger->error('{db} is missing - aborted recalculating hashes', [ 'db' => $this->dbPrefix . OptionMapper::TABLE]);
+ $this->logger->info('Updated {updated} hashes of {count} options in {db}', [
+ 'updated' => $updated,
+ 'count' => $count,
+ 'db' => $this->dbPrefix . OptionMapper::TABLE
+ ]);
+ $messages[] = 'Updated ' . $updated . ' option hashes';
+
}
+
return $messages;
}
@@ -667,4 +684,52 @@ public function updateHashes(): array {
$messages = array_merge($messages, $this->updateVoteHashes($schema));
return $messages;
}
+
+ /**
+ * @return string[]
+ *
+ * @psalm-return list{0?: string,...}
+ */
+ public function migrateShareLabels(): array {
+ $schema = $this->connection->createSchema();
+ $messages = [];
+
+ if (!$schema->hasTable($this->dbPrefix . Share::TABLE)) {
+ $this->logger->error('{db} is missing - aborted migrating labels', [ 'db' => $this->dbPrefix . Share::TABLE]);
+ $messages[] = 'Table ' . $this->dbPrefix . Share::TABLE . ' does not exist';
+ return $messages;
+ }
+ $table = $schema->getTable($this->dbPrefix . Share::TABLE);
+
+ if (!$table->hasColumn('label')) {
+ $this->logger->error('{db} is missing column \'label\' - aborted migrating labels', [ 'db' => $this->dbPrefix . Share::TABLE]);
+ $messages[] = 'Column \'label\' does not exist in ' . $this->dbPrefix . Share::TABLE;
+ return $messages;
+ }
+
+ $qb = $this->connection->getQueryBuilder();
+
+ $qb->update(Share::TABLE)
+ ->set('display_name', 'label') // safe: assigns column B's value into A
+ ->andWhere($qb->expr()->isNotNull(Share::TABLE . '.label'))
+ ->andWhere($qb->expr()->eq(Share::TABLE . '.label', $qb->expr()->literal('')));
+ $updated = $qb->executeStatement();
+
+ if ($updated === 0) {
+ $this->logger->info('Verified all share labels in {db}', [
+ 'db' => $this->dbPrefix . Share::TABLE
+ ]);
+ $messages[] = 'No share labels to update';
+
+ } else {
+ $this->logger->info('Updated {updated} labels in {db}', [
+ 'updated' => $updated,
+ 'db' => $this->dbPrefix . Share::TABLE
+ ]);
+ $messages[] = 'Updated ' . $updated . ' option hashes';
+
+ }
+
+ return $messages;
+ }
}
diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php
index 3cc72e7f16..7cfc718107 100644
--- a/lib/Service/ShareService.php
+++ b/lib/Service/ShareService.php
@@ -295,10 +295,6 @@ public function setLabel(string $label, string $token): Share {
->request(Poll::PERMISSION_POLL_EDIT);
$this->share->setLabel($label);
- // overwrite any possible displayName
- // TODO: Remove afte rmigratiuon to label
- $this->share->setDisplayName('');
-
$dispatchEvent = new ShareChangedLabelEvent($this->share);
} else {
throw new InvalidShareTypeException('Label can only be set for public shares.');
diff --git a/src/components/Combo/ComboTable.vue b/src/components/Combo/ComboTable.vue
index 3d093f8eaf..5d611dd52b 100644
--- a/src/components/Combo/ComboTable.vue
+++ b/src/components/Combo/ComboTable.vue
@@ -28,7 +28,7 @@ const comboStore = useComboStore()
v-for="participant in comboStore.participantsInPoll(poll.id)"
:key="`${participant.user.id}_${participant.pollId}`"
class="participant">
-
+
diff --git a/src/components/Options/OptionItemOwner.vue b/src/components/Options/OptionItemOwner.vue
index 5239af098f..4732f81570 100644
--- a/src/components/Options/OptionItemOwner.vue
+++ b/src/components/Options/OptionItemOwner.vue
@@ -51,7 +51,6 @@ const showDelete = computed(
:user="option.owner"
:icon-size="avatarSize"
hide-names
- hide-status
:tooltip-message="
t('polls', '{displayName}\'s proposal', {
displayName: option.owner?.displayName ?? '',
diff --git a/src/components/Shares/ShareItem.vue b/src/components/Shares/ShareItem.vue
index cf69f5fcd6..e328b939bb 100644
--- a/src/components/Shares/ShareItem.vue
+++ b/src/components/Shares/ShareItem.vue
@@ -4,7 +4,7 @@
-->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/User/UserBubble.vue b/src/components/User/UserBubble.vue
index 0da66990de..520d7a4ddf 100644
--- a/src/components/User/UserBubble.vue
+++ b/src/components/User/UserBubble.vue
@@ -9,31 +9,13 @@ import { t } from '@nextcloud/l10n'
import NcUserBubble from '@nextcloud/vue/components/NcUserBubble'
-import type { User } from '../../Types'
+import { createDefault, type User } from '../../Types'
interface Props {
user: User
}
-const {
- user = {
- id: '',
- displayName: '',
- emailAddress: '',
- isNoUser: true,
- isAdmin: false,
- isGuest: false,
- type: '',
- subName: null,
- subtitle: null,
- desc: null,
- organisation: null,
- languageCode: '',
- localeCode: null,
- timeZone: null,
- categories: null,
- },
-} = defineProps()
+const { user = createDefault() } = defineProps()
const bubbleProps = computed(() => ({
user: user.isNoUser || user.isGuest ? undefined : user.id,
diff --git a/src/components/User/UserItem.vue b/src/components/User/UserItem.vue
index 2c08888b76..4f6d3d2c0d 100644
--- a/src/components/User/UserItem.vue
+++ b/src/components/User/UserItem.vue
@@ -5,205 +5,86 @@