migrations.js 21 KB

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