migrations.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. import { TAPi18n } from '/imports/i18n';
  2. import AccountSettings from '../models/accountSettings';
  3. import TableVisibilityModeSettings from '../models/tableVisibilityModeSettings';
  4. import Actions from '../models/actions';
  5. import Activities from '../models/activities';
  6. import Announcements from '../models/announcements';
  7. import Boards from '../models/boards';
  8. import CardComments from '../models/cardComments';
  9. import Cards from '../models/cards';
  10. import ChecklistItems from '../models/checklistItems';
  11. import Checklists from '../models/checklists';
  12. import CustomFields from '../models/customFields';
  13. import Integrations from '../models/integrations';
  14. import InvitationCodes from '../models/invitationCodes';
  15. import Lists from '../models/lists';
  16. import Rules from '../models/rules';
  17. import Settings from '../models/settings';
  18. import Swimlanes from '../models/swimlanes';
  19. import Triggers from '../models/triggers';
  20. import UnsavedEdits from '../models/unsavedEdits';
  21. import Users from '../models/users';
  22. // Anytime you change the schema of one of the collection in a non-backward
  23. // compatible way you have to write a migration in this file using the following
  24. // API:
  25. //
  26. // Migrations.add(name, migrationCallback, optionalOrder);
  27. // Note that we have extra migrations defined in `sandstorm.js` that are
  28. // exclusive to Sandstorm and shouldn’t be executed in the general case.
  29. // XXX I guess if we had ES6 modules we could
  30. // `import { isSandstorm } from sandstorm.js` and define the migration here as
  31. // well, but for now I want to avoid definied too many globals.
  32. // In the context of migration functions we don't want to validate database
  33. // mutation queries against the current (ie, latest) collection schema. Doing
  34. // that would work at the time we write the migration but would break in the
  35. // future when we'll update again the concerned collection schema.
  36. //
  37. // To prevent this bug we always have to disable the schema validation and
  38. // argument transformations. We generally use the shorthandlers defined below.
  39. const noValidate = {
  40. validate: false,
  41. filter: false,
  42. autoConvert: false,
  43. removeEmptyStrings: false,
  44. getAutoValues: false,
  45. };
  46. const noValidateMulti = { ...noValidate, multi: true };
  47. Migrations.add('board-background-color', () => {
  48. const defaultColor = '#16A085';
  49. Boards.update(
  50. {
  51. background: {
  52. $exists: false,
  53. },
  54. },
  55. {
  56. $set: {
  57. background: {
  58. type: 'color',
  59. color: defaultColor,
  60. },
  61. },
  62. },
  63. noValidateMulti,
  64. );
  65. });
  66. Migrations.add('lowercase-board-permission', () => {
  67. ['Public', 'Private'].forEach(permission => {
  68. Boards.update(
  69. { permission },
  70. { $set: { permission: permission.toLowerCase() } },
  71. noValidateMulti,
  72. );
  73. });
  74. });
  75. /*
  76. // Security migration: see https://github.com/wekan/wekan/issues/99
  77. Migrations.add('change-attachments-type-for-non-images', () => {
  78. const newTypeForNonImage = 'application/octet-stream';
  79. Attachments.find().forEach(file => {
  80. if (!file.isImage()) {
  81. Attachments.update(
  82. file._id,
  83. {
  84. $set: {
  85. 'original.type': newTypeForNonImage,
  86. 'copies.attachments.type': newTypeForNonImage,
  87. },
  88. },
  89. noValidate,
  90. );
  91. }
  92. });
  93. });
  94. Migrations.add('card-covers', () => {
  95. Cards.find().forEach(card => {
  96. const cover = Attachments.findOne({ cardId: card._id, cover: true });
  97. if (cover) {
  98. Cards.update(card._id, { $set: { coverId: cover._id } }, noValidate);
  99. }
  100. });
  101. Attachments.update({}, { $unset: { cover: '' } }, noValidateMulti);
  102. });
  103. */
  104. Migrations.add('use-css-class-for-boards-colors', () => {
  105. const associationTable = {
  106. '#27AE60': 'nephritis',
  107. '#C0392B': 'pomegranate',
  108. '#2980B9': 'belize',
  109. '#8E44AD': 'wisteria',
  110. '#2C3E50': 'midnight',
  111. '#E67E22': 'pumpkin',
  112. '#CD5A91': 'moderatepink',
  113. '#00AECC': 'strongcyan',
  114. '#4BBF6B': 'limegreen',
  115. '#2C3E51': 'dark',
  116. '#27AE61': 'relax',
  117. '#568BA2': 'corteza',
  118. '#499BEA': 'clearblue',
  119. '#596557': 'natural',
  120. '#2A80B8': 'modern',
  121. '#2a2a2a': 'moderndark',
  122. };
  123. Boards.find().forEach(board => {
  124. const oldBoardColor = board.background.color;
  125. const newBoardColor = associationTable[oldBoardColor];
  126. Boards.update(
  127. board._id,
  128. {
  129. $set: { color: newBoardColor },
  130. $unset: { background: '' },
  131. },
  132. noValidate,
  133. );
  134. });
  135. });
  136. Migrations.add('denormalize-star-number-per-board', () => {
  137. Boards.find().forEach(board => {
  138. const nStars = Users.find({ 'profile.starredBoards': board._id }).count();
  139. Boards.update(board._id, { $set: { stars: nStars } }, noValidate);
  140. });
  141. });
  142. // We want to keep a trace of former members so we can efficiently publish their
  143. // infos in the general board publication.
  144. Migrations.add('add-member-isactive-field', () => {
  145. Boards.find({}, { fields: { members: 1 } }).forEach(board => {
  146. const allUsersWithSomeActivity = _.chain(
  147. Activities.find(
  148. { boardId: board._id },
  149. { fields: { userId: 1 } },
  150. ).fetch(),
  151. )
  152. .pluck('userId')
  153. .uniq()
  154. .value();
  155. const currentUsers = _.pluck(board.members, 'userId');
  156. const formerUsers = _.difference(allUsersWithSomeActivity, currentUsers);
  157. const newMemberSet = [];
  158. board.members.forEach(member => {
  159. member.isActive = true;
  160. newMemberSet.push(member);
  161. });
  162. formerUsers.forEach(userId => {
  163. newMemberSet.push({
  164. userId,
  165. isAdmin: false,
  166. isActive: false,
  167. });
  168. });
  169. Boards.update(board._id, { $set: { members: newMemberSet } }, noValidate);
  170. });
  171. });
  172. Migrations.add('add-sort-checklists', () => {
  173. Checklists.find().forEach((checklist, index) => {
  174. if (!checklist.hasOwnProperty('sort')) {
  175. Checklists.direct.update(
  176. checklist._id,
  177. { $set: { sort: index } },
  178. noValidate,
  179. );
  180. }
  181. checklist.items.forEach((item, index) => {
  182. if (!item.hasOwnProperty('sort')) {
  183. Checklists.direct.update(
  184. { _id: checklist._id, 'items._id': item._id },
  185. { $set: { 'items.$.sort': index } },
  186. noValidate,
  187. );
  188. }
  189. });
  190. });
  191. });
  192. Migrations.add('add-swimlanes', () => {
  193. Boards.find().forEach(board => {
  194. const swimlaneId = board.getDefaultSwimline()._id;
  195. Cards.find({ boardId: board._id }).forEach(card => {
  196. if (!card.hasOwnProperty('swimlaneId')) {
  197. Cards.direct.update(
  198. { _id: card._id },
  199. { $set: { swimlaneId } },
  200. noValidate,
  201. );
  202. }
  203. });
  204. });
  205. });
  206. Migrations.add('add-views', () => {
  207. Boards.find().forEach(board => {
  208. if (!board.hasOwnProperty('view')) {
  209. Boards.direct.update(
  210. { _id: board._id },
  211. { $set: { view: 'board-view-swimlanes' } },
  212. noValidate,
  213. );
  214. }
  215. });
  216. });
  217. Migrations.add('add-checklist-items', () => {
  218. Checklists.find().forEach(checklist => {
  219. // Create new items
  220. _.sortBy(checklist.items, 'sort').forEach((item, index) => {
  221. ChecklistItems.direct.insert({
  222. title: item.title ? item.title : 'Checklist',
  223. sort: index,
  224. isFinished: item.isFinished,
  225. checklistId: checklist._id,
  226. cardId: checklist.cardId,
  227. });
  228. });
  229. // Delete old ones
  230. Checklists.direct.update(
  231. { _id: checklist._id },
  232. { $unset: { items: 1 } },
  233. noValidate,
  234. );
  235. });
  236. });
  237. Migrations.add('add-card-types', () => {
  238. Cards.find().forEach(card => {
  239. Cards.direct.update(
  240. { _id: card._id },
  241. {
  242. $set: {
  243. type: 'cardType-card',
  244. linkedId: null,
  245. },
  246. },
  247. noValidate,
  248. );
  249. });
  250. });
  251. Migrations.add('add-custom-fields-to-cards', () => {
  252. Cards.update(
  253. {
  254. customFields: {
  255. $exists: false,
  256. },
  257. },
  258. {
  259. $set: {
  260. customFields: [],
  261. },
  262. },
  263. noValidateMulti,
  264. );
  265. });
  266. Migrations.add('add-requester-field', () => {
  267. Cards.update(
  268. {
  269. requestedBy: {
  270. $exists: false,
  271. },
  272. },
  273. {
  274. $set: {
  275. requestedBy: '',
  276. },
  277. },
  278. noValidateMulti,
  279. );
  280. });
  281. Migrations.add('add-assigner-field', () => {
  282. Cards.update(
  283. {
  284. assignedBy: {
  285. $exists: false,
  286. },
  287. },
  288. {
  289. $set: {
  290. assignedBy: '',
  291. },
  292. },
  293. noValidateMulti,
  294. );
  295. });
  296. Migrations.add('add-parent-field-to-cards', () => {
  297. Cards.update(
  298. {
  299. parentId: {
  300. $exists: false,
  301. },
  302. },
  303. {
  304. $set: {
  305. parentId: '',
  306. },
  307. },
  308. noValidateMulti,
  309. );
  310. });
  311. Migrations.add('add-subtasks-boards', () => {
  312. Boards.update(
  313. {
  314. subtasksDefaultBoardId: {
  315. $exists: false,
  316. },
  317. },
  318. {
  319. $set: {
  320. subtasksDefaultBoardId: null,
  321. subtasksDefaultListId: null,
  322. },
  323. },
  324. noValidateMulti,
  325. );
  326. });
  327. Migrations.add('add-subtasks-sort', () => {
  328. Boards.update(
  329. {
  330. subtaskSort: {
  331. $exists: false,
  332. },
  333. },
  334. {
  335. $set: {
  336. subtaskSort: -1,
  337. },
  338. },
  339. noValidateMulti,
  340. );
  341. });
  342. Migrations.add('add-subtasks-allowed', () => {
  343. Boards.update(
  344. {
  345. allowsSubtasks: {
  346. $exists: false,
  347. },
  348. },
  349. {
  350. $set: {
  351. allowsSubtasks: true,
  352. },
  353. },
  354. noValidateMulti,
  355. );
  356. });
  357. Migrations.add('add-subtasks-allowed', () => {
  358. Boards.update(
  359. {
  360. presentParentTask: {
  361. $exists: false,
  362. },
  363. },
  364. {
  365. $set: {
  366. presentParentTask: 'no-parent',
  367. },
  368. },
  369. noValidateMulti,
  370. );
  371. });
  372. Migrations.add('add-authenticationMethod', () => {
  373. Users.update(
  374. {
  375. authenticationMethod: {
  376. $exists: false,
  377. },
  378. },
  379. {
  380. $set: {
  381. authenticationMethod: 'password',
  382. },
  383. },
  384. noValidateMulti,
  385. );
  386. });
  387. Migrations.add('remove-tag', () => {
  388. Users.update(
  389. {},
  390. {
  391. $unset: {
  392. 'profile.tags': 1,
  393. },
  394. },
  395. noValidateMulti,
  396. );
  397. });
  398. Migrations.add('remove-customFields-references-broken', () => {
  399. Cards.update(
  400. { 'customFields.$value': null },
  401. {
  402. $pull: {
  403. customFields: { value: null },
  404. },
  405. },
  406. noValidateMulti,
  407. );
  408. });
  409. Migrations.add('add-product-name', () => {
  410. Settings.update(
  411. {
  412. productName: {
  413. $exists: false,
  414. },
  415. },
  416. {
  417. $set: {
  418. productName: '',
  419. },
  420. },
  421. noValidateMulti,
  422. );
  423. });
  424. Migrations.add('add-hide-logo', () => {
  425. Settings.update(
  426. {
  427. hideLogo: {
  428. $exists: false,
  429. },
  430. },
  431. {
  432. $set: {
  433. hideLogo: false,
  434. },
  435. },
  436. noValidateMulti,
  437. );
  438. });
  439. Migrations.add('add-displayAuthenticationMethod', () => {
  440. Settings.update(
  441. {
  442. displayAuthenticationMethod: {
  443. $exists: false,
  444. },
  445. },
  446. {
  447. $set: {
  448. displayAuthenticationMethod: true,
  449. },
  450. },
  451. noValidateMulti,
  452. );
  453. });
  454. Migrations.add('add-defaultAuthenticationMethod', () => {
  455. Settings.update(
  456. {
  457. defaultAuthenticationMethod: {
  458. $exists: false,
  459. },
  460. },
  461. {
  462. $set: {
  463. defaultAuthenticationMethod: 'password',
  464. },
  465. },
  466. noValidateMulti,
  467. );
  468. });
  469. Migrations.add('add-templates', () => {
  470. Boards.update(
  471. {
  472. type: {
  473. $exists: false,
  474. },
  475. },
  476. {
  477. $set: {
  478. type: 'board',
  479. },
  480. },
  481. noValidateMulti,
  482. );
  483. Swimlanes.update(
  484. {
  485. type: {
  486. $exists: false,
  487. },
  488. },
  489. {
  490. $set: {
  491. type: 'swimlane',
  492. },
  493. },
  494. noValidateMulti,
  495. );
  496. Lists.update(
  497. {
  498. type: {
  499. $exists: false,
  500. },
  501. swimlaneId: {
  502. $exists: false,
  503. },
  504. },
  505. {
  506. $set: {
  507. type: 'list',
  508. swimlaneId: '',
  509. },
  510. },
  511. noValidateMulti,
  512. );
  513. Users.find({
  514. 'profile.templatesBoardId': {
  515. $exists: false,
  516. },
  517. }).forEach(user => {
  518. // Create board and swimlanes
  519. Boards.insert(
  520. {
  521. title: TAPi18n.__('templates'),
  522. permission: 'private',
  523. type: 'template-container',
  524. members: [
  525. {
  526. userId: user._id,
  527. isAdmin: true,
  528. isActive: true,
  529. isNoComments: false,
  530. isCommentOnly: false,
  531. },
  532. ],
  533. },
  534. (err, boardId) => {
  535. // Insert the reference to our templates board
  536. Users.update(user._id, {
  537. $set: { 'profile.templatesBoardId': boardId },
  538. });
  539. // Insert the card templates swimlane
  540. Swimlanes.insert(
  541. {
  542. title: TAPi18n.__('card-templates-swimlane'),
  543. boardId,
  544. sort: 1,
  545. type: 'template-container',
  546. },
  547. (err, swimlaneId) => {
  548. // Insert the reference to out card templates swimlane
  549. Users.update(user._id, {
  550. $set: { 'profile.cardTemplatesSwimlaneId': swimlaneId },
  551. });
  552. },
  553. );
  554. // Insert the list templates swimlane
  555. Swimlanes.insert(
  556. {
  557. title: TAPi18n.__('list-templates-swimlane'),
  558. boardId,
  559. sort: 2,
  560. type: 'template-container',
  561. },
  562. (err, swimlaneId) => {
  563. // Insert the reference to out list templates swimlane
  564. Users.update(user._id, {
  565. $set: { 'profile.listTemplatesSwimlaneId': swimlaneId },
  566. });
  567. },
  568. );
  569. // Insert the board templates swimlane
  570. Swimlanes.insert(
  571. {
  572. title: TAPi18n.__('board-templates-swimlane'),
  573. boardId,
  574. sort: 3,
  575. type: 'template-container',
  576. },
  577. (err, swimlaneId) => {
  578. // Insert the reference to out board templates swimlane
  579. Users.update(user._id, {
  580. $set: { 'profile.boardTemplatesSwimlaneId': swimlaneId },
  581. });
  582. },
  583. );
  584. },
  585. );
  586. });
  587. });
  588. Migrations.add('fix-circular-reference_', () => {
  589. Cards.find().forEach(card => {
  590. if (card.parentId === card._id) {
  591. Cards.update(card._id, { $set: { parentId: '' } }, noValidateMulti);
  592. }
  593. });
  594. });
  595. Migrations.add('mutate-boardIds-in-customfields', () => {
  596. CustomFields.find().forEach(cf => {
  597. CustomFields.update(
  598. cf,
  599. {
  600. $set: {
  601. boardIds: [cf.boardId],
  602. },
  603. $unset: {
  604. boardId: '',
  605. },
  606. },
  607. noValidateMulti,
  608. );
  609. });
  610. });
  611. const modifiedAtTables = [
  612. AccountSettings,
  613. TableVisibilityModeSettings,
  614. Actions,
  615. Activities,
  616. Announcements,
  617. Boards,
  618. CardComments,
  619. Cards,
  620. ChecklistItems,
  621. Checklists,
  622. CustomFields,
  623. Integrations,
  624. InvitationCodes,
  625. Lists,
  626. Rules,
  627. Settings,
  628. Swimlanes,
  629. Triggers,
  630. UnsavedEdits,
  631. Users,
  632. ];
  633. Migrations.add('add-missing-created-and-modified', () => {
  634. Promise.all(
  635. modifiedAtTables.map(db =>
  636. db
  637. .rawCollection()
  638. .update(
  639. { modifiedAt: { $exists: false } },
  640. { $set: { modifiedAt: new Date() } },
  641. { multi: true },
  642. )
  643. .then(() =>
  644. db
  645. .rawCollection()
  646. .update(
  647. { createdAt: { $exists: false } },
  648. { $set: { createdAt: new Date() } },
  649. { multi: true },
  650. ),
  651. ),
  652. ),
  653. )
  654. .then(() => {
  655. // eslint-disable-next-line no-console
  656. console.info('Successfully added createdAt and updatedAt to all tables');
  657. })
  658. .catch(e => {
  659. // eslint-disable-next-line no-console
  660. console.error(e);
  661. });
  662. });
  663. Migrations.add('fix-incorrect-dates', () => {
  664. const tables = [
  665. AccountSettings,
  666. TableVisibilityModeSettings,
  667. Actions,
  668. Activities,
  669. Announcements,
  670. Boards,
  671. CardComments,
  672. Cards,
  673. ChecklistItems,
  674. Checklists,
  675. CustomFields,
  676. Integrations,
  677. InvitationCodes,
  678. Lists,
  679. Rules,
  680. Settings,
  681. Swimlanes,
  682. Triggers,
  683. UnsavedEdits,
  684. ];
  685. // Dates were previously created with Date.now() which is a number, not a date
  686. tables.forEach(t =>
  687. t
  688. .rawCollection()
  689. .find({ $or: [{ createdAt: { $type: 1 } }, { updatedAt: { $type: 1 } }] })
  690. .forEach(({ _id, createdAt, updatedAt }) => {
  691. t.rawCollection().update(
  692. { _id },
  693. {
  694. $set: {
  695. createdAt: new Date(createdAt),
  696. updatedAt: new Date(updatedAt),
  697. },
  698. },
  699. );
  700. }),
  701. );
  702. });
  703. Migrations.add('add-assignee', () => {
  704. Cards.update(
  705. {
  706. assignees: {
  707. $exists: false,
  708. },
  709. },
  710. {
  711. $set: {
  712. assignees: [],
  713. },
  714. },
  715. noValidateMulti,
  716. );
  717. });
  718. Migrations.add('add-profile-showDesktopDragHandles', () => {
  719. Users.update(
  720. {
  721. 'profile.showDesktopDragHandles': {
  722. $exists: false,
  723. },
  724. },
  725. {
  726. $set: {
  727. 'profile.showDesktopDragHandles': false,
  728. },
  729. },
  730. noValidateMulti,
  731. );
  732. });
  733. Migrations.add('add-profile-hiddenMinicardLabelText', () => {
  734. Users.update(
  735. {
  736. 'profile.hiddenMinicardLabelText': {
  737. $exists: false,
  738. },
  739. },
  740. {
  741. $set: {
  742. 'profile.hiddenMinicardLabelText': false,
  743. },
  744. },
  745. noValidateMulti,
  746. );
  747. });
  748. Migrations.add('add-receiveddate-allowed', () => {
  749. Boards.update(
  750. {
  751. allowsReceivedDate: {
  752. $exists: false,
  753. },
  754. },
  755. {
  756. $set: {
  757. allowsReceivedDate: true,
  758. },
  759. },
  760. noValidateMulti,
  761. );
  762. });
  763. Migrations.add('add-startdate-allowed', () => {
  764. Boards.update(
  765. {
  766. allowsStartDate: {
  767. $exists: false,
  768. },
  769. },
  770. {
  771. $set: {
  772. allowsStartDate: true,
  773. },
  774. },
  775. noValidateMulti,
  776. );
  777. });
  778. Migrations.add('add-duedate-allowed', () => {
  779. Boards.update(
  780. {
  781. allowsDueDate: {
  782. $exists: false,
  783. },
  784. },
  785. {
  786. $set: {
  787. allowsDueDate: true,
  788. },
  789. },
  790. noValidateMulti,
  791. );
  792. });
  793. Migrations.add('add-enddate-allowed', () => {
  794. Boards.update(
  795. {
  796. allowsEndDate: {
  797. $exists: false,
  798. },
  799. },
  800. {
  801. $set: {
  802. allowsEndDate: true,
  803. },
  804. },
  805. noValidateMulti,
  806. );
  807. });
  808. Migrations.add('add-members-allowed', () => {
  809. Boards.update(
  810. {
  811. allowsMembers: {
  812. $exists: false,
  813. },
  814. },
  815. {
  816. $set: {
  817. allowsMembers: true,
  818. },
  819. },
  820. noValidateMulti,
  821. );
  822. });
  823. Migrations.add('add-assignee-allowed', () => {
  824. Boards.update(
  825. {
  826. allowsAssignee: {
  827. $exists: false,
  828. },
  829. },
  830. {
  831. $set: {
  832. allowsAssignee: true,
  833. },
  834. },
  835. noValidateMulti,
  836. );
  837. });
  838. Migrations.add('add-labels-allowed', () => {
  839. Boards.update(
  840. {
  841. allowsLabels: {
  842. $exists: false,
  843. },
  844. },
  845. {
  846. $set: {
  847. allowsLabels: true,
  848. },
  849. },
  850. noValidateMulti,
  851. );
  852. });
  853. Migrations.add('add-checklists-allowed', () => {
  854. Boards.update(
  855. {
  856. allowsChecklists: {
  857. $exists: false,
  858. },
  859. },
  860. {
  861. $set: {
  862. allowsChecklists: true,
  863. },
  864. },
  865. noValidateMulti,
  866. );
  867. });
  868. Migrations.add('add-attachments-allowed', () => {
  869. Boards.update(
  870. {
  871. allowsAttachments: {
  872. $exists: false,
  873. },
  874. },
  875. {
  876. $set: {
  877. allowsAttachments: true,
  878. },
  879. },
  880. noValidateMulti,
  881. );
  882. });
  883. Migrations.add('add-comments-allowed', () => {
  884. Boards.update(
  885. {
  886. allowsComments: {
  887. $exists: false,
  888. },
  889. },
  890. {
  891. $set: {
  892. allowsComments: true,
  893. },
  894. },
  895. noValidateMulti,
  896. );
  897. });
  898. Migrations.add('add-assigned-by-allowed', () => {
  899. Boards.update(
  900. {
  901. allowsAssignedBy: {
  902. $exists: false,
  903. },
  904. },
  905. {
  906. $set: {
  907. allowsAssignedBy: true,
  908. },
  909. },
  910. noValidateMulti,
  911. );
  912. });
  913. Migrations.add('add-requested-by-allowed', () => {
  914. Boards.update(
  915. {
  916. allowsRequestedBy: {
  917. $exists: false,
  918. },
  919. },
  920. {
  921. $set: {
  922. allowsRequestedBy: true,
  923. },
  924. },
  925. noValidateMulti,
  926. );
  927. });
  928. Migrations.add('add-activities-allowed', () => {
  929. Boards.update(
  930. {
  931. allowsActivities: {
  932. $exists: false,
  933. },
  934. },
  935. {
  936. $set: {
  937. allowsActivities: true,
  938. },
  939. },
  940. noValidateMulti,
  941. );
  942. });
  943. Migrations.add('add-description-title-allowed', () => {
  944. Boards.update(
  945. {
  946. allowsDescriptionTitle: {
  947. $exists: false,
  948. },
  949. },
  950. {
  951. $set: {
  952. allowsDescriptionTitle: true,
  953. },
  954. },
  955. noValidateMulti,
  956. );
  957. });
  958. Migrations.add('add-description-text-allowed', () => {
  959. Boards.update(
  960. {
  961. allowsDescriptionText: {
  962. $exists: false,
  963. },
  964. },
  965. {
  966. $set: {
  967. allowsDescriptionText: true,
  968. },
  969. },
  970. noValidateMulti,
  971. );
  972. });
  973. Migrations.add('add-sort-field-to-boards', () => {
  974. Boards.find().forEach((board, index) => {
  975. if (!board.hasOwnProperty('sort')) {
  976. Boards.direct.update(board._id, { $set: { sort: index } }, noValidate);
  977. }
  978. });
  979. });
  980. Migrations.add('add-default-profile-view', () => {
  981. Users.find().forEach(user => {
  982. if (!user.hasOwnProperty('profile.boardView')) {
  983. // Set default view
  984. Users.direct.update(
  985. { _id: user._id },
  986. { $set: { 'profile.boardView': 'board-view-swimlanes' } },
  987. noValidate,
  988. );
  989. }
  990. });
  991. });
  992. Migrations.add('add-hide-logo-by-default', () => {
  993. Settings.update(
  994. {
  995. hideLogo: {
  996. hideLogo: false,
  997. },
  998. },
  999. {
  1000. $set: {
  1001. hideLogo: true,
  1002. },
  1003. },
  1004. noValidateMulti,
  1005. );
  1006. });
  1007. Migrations.add('add-card-number-allowed', () => {
  1008. Boards.update(
  1009. {
  1010. allowsCardNumber: {
  1011. $exists: false,
  1012. },
  1013. },
  1014. {
  1015. $set: {
  1016. allowsCardNumber: false,
  1017. },
  1018. },
  1019. noValidateMulti,
  1020. );
  1021. });
  1022. Migrations.add('assign-boardwise-card-numbers', () => {
  1023. Boards.find().forEach(board => {
  1024. let nextCardNumber = board.getNextCardNumber();
  1025. Cards.find(
  1026. {
  1027. boardId: board._id,
  1028. cardNumber: {
  1029. $exists: false
  1030. }
  1031. },
  1032. {
  1033. sort: { createdAt: 1 }
  1034. }
  1035. ).forEach(card => {
  1036. Cards.update(
  1037. card._id,
  1038. { $set: { cardNumber: nextCardNumber } },
  1039. noValidate);
  1040. nextCardNumber++;
  1041. });
  1042. })
  1043. });
  1044. Migrations.add('add-card-details-show-lists', () => {
  1045. Boards.update(
  1046. {
  1047. allowsShowLists: {
  1048. $exists: false,
  1049. },
  1050. },
  1051. {
  1052. $set: {
  1053. allowsShowLists: true,
  1054. },
  1055. },
  1056. noValidateMulti,
  1057. );
  1058. });