migrations.js 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  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. '#596557': 'natural',
  116. '#2A80B8': 'modern',
  117. };
  118. Boards.find().forEach(board => {
  119. const oldBoardColor = board.background.color;
  120. const newBoardColor = associationTable[oldBoardColor];
  121. Boards.update(
  122. board._id,
  123. {
  124. $set: { color: newBoardColor },
  125. $unset: { background: '' },
  126. },
  127. noValidate,
  128. );
  129. });
  130. });
  131. Migrations.add('denormalize-star-number-per-board', () => {
  132. Boards.find().forEach(board => {
  133. const nStars = Users.find({ 'profile.starredBoards': board._id }).count();
  134. Boards.update(board._id, { $set: { stars: nStars } }, noValidate);
  135. });
  136. });
  137. // We want to keep a trace of former members so we can efficiently publish their
  138. // infos in the general board publication.
  139. Migrations.add('add-member-isactive-field', () => {
  140. Boards.find({}, { fields: { members: 1 } }).forEach(board => {
  141. const allUsersWithSomeActivity = _.chain(
  142. Activities.find(
  143. { boardId: board._id },
  144. { fields: { userId: 1 } },
  145. ).fetch(),
  146. )
  147. .pluck('userId')
  148. .uniq()
  149. .value();
  150. const currentUsers = _.pluck(board.members, 'userId');
  151. const formerUsers = _.difference(allUsersWithSomeActivity, currentUsers);
  152. const newMemberSet = [];
  153. board.members.forEach(member => {
  154. member.isActive = true;
  155. newMemberSet.push(member);
  156. });
  157. formerUsers.forEach(userId => {
  158. newMemberSet.push({
  159. userId,
  160. isAdmin: false,
  161. isActive: false,
  162. });
  163. });
  164. Boards.update(board._id, { $set: { members: newMemberSet } }, noValidate);
  165. });
  166. });
  167. Migrations.add('add-sort-checklists', () => {
  168. Checklists.find().forEach((checklist, index) => {
  169. if (!checklist.hasOwnProperty('sort')) {
  170. Checklists.direct.update(
  171. checklist._id,
  172. { $set: { sort: index } },
  173. noValidate,
  174. );
  175. }
  176. checklist.items.forEach((item, index) => {
  177. if (!item.hasOwnProperty('sort')) {
  178. Checklists.direct.update(
  179. { _id: checklist._id, 'items._id': item._id },
  180. { $set: { 'items.$.sort': index } },
  181. noValidate,
  182. );
  183. }
  184. });
  185. });
  186. });
  187. Migrations.add('add-swimlanes', () => {
  188. Boards.find().forEach(board => {
  189. const swimlaneId = board.getDefaultSwimline()._id;
  190. Cards.find({ boardId: board._id }).forEach(card => {
  191. if (!card.hasOwnProperty('swimlaneId')) {
  192. Cards.direct.update(
  193. { _id: card._id },
  194. { $set: { swimlaneId } },
  195. noValidate,
  196. );
  197. }
  198. });
  199. });
  200. });
  201. Migrations.add('add-views', () => {
  202. Boards.find().forEach(board => {
  203. if (!board.hasOwnProperty('view')) {
  204. Boards.direct.update(
  205. { _id: board._id },
  206. { $set: { view: 'board-view-swimlanes' } },
  207. noValidate,
  208. );
  209. }
  210. });
  211. });
  212. Migrations.add('add-checklist-items', () => {
  213. Checklists.find().forEach(checklist => {
  214. // Create new items
  215. _.sortBy(checklist.items, 'sort').forEach((item, index) => {
  216. ChecklistItems.direct.insert({
  217. title: item.title ? item.title : 'Checklist',
  218. sort: index,
  219. isFinished: item.isFinished,
  220. checklistId: checklist._id,
  221. cardId: checklist.cardId,
  222. });
  223. });
  224. // Delete old ones
  225. Checklists.direct.update(
  226. { _id: checklist._id },
  227. { $unset: { items: 1 } },
  228. noValidate,
  229. );
  230. });
  231. });
  232. Migrations.add('add-profile-view', () => {
  233. Users.find().forEach(user => {
  234. if (!user.hasOwnProperty('profile.boardView')) {
  235. // Set default view
  236. Users.direct.update(
  237. { _id: user._id },
  238. { $set: { 'profile.boardView': 'board-view-lists' } },
  239. noValidate,
  240. );
  241. }
  242. });
  243. });
  244. Migrations.add('add-card-types', () => {
  245. Cards.find().forEach(card => {
  246. Cards.direct.update(
  247. { _id: card._id },
  248. {
  249. $set: {
  250. type: 'cardType-card',
  251. linkedId: null,
  252. },
  253. },
  254. noValidate,
  255. );
  256. });
  257. });
  258. Migrations.add('add-custom-fields-to-cards', () => {
  259. Cards.update(
  260. {
  261. customFields: {
  262. $exists: false,
  263. },
  264. },
  265. {
  266. $set: {
  267. customFields: [],
  268. },
  269. },
  270. noValidateMulti,
  271. );
  272. });
  273. Migrations.add('add-requester-field', () => {
  274. Cards.update(
  275. {
  276. requestedBy: {
  277. $exists: false,
  278. },
  279. },
  280. {
  281. $set: {
  282. requestedBy: '',
  283. },
  284. },
  285. noValidateMulti,
  286. );
  287. });
  288. Migrations.add('add-assigner-field', () => {
  289. Cards.update(
  290. {
  291. assignedBy: {
  292. $exists: false,
  293. },
  294. },
  295. {
  296. $set: {
  297. assignedBy: '',
  298. },
  299. },
  300. noValidateMulti,
  301. );
  302. });
  303. Migrations.add('add-parent-field-to-cards', () => {
  304. Cards.update(
  305. {
  306. parentId: {
  307. $exists: false,
  308. },
  309. },
  310. {
  311. $set: {
  312. parentId: '',
  313. },
  314. },
  315. noValidateMulti,
  316. );
  317. });
  318. Migrations.add('add-subtasks-boards', () => {
  319. Boards.update(
  320. {
  321. subtasksDefaultBoardId: {
  322. $exists: false,
  323. },
  324. },
  325. {
  326. $set: {
  327. subtasksDefaultBoardId: null,
  328. subtasksDefaultListId: null,
  329. },
  330. },
  331. noValidateMulti,
  332. );
  333. });
  334. Migrations.add('add-subtasks-sort', () => {
  335. Boards.update(
  336. {
  337. subtaskSort: {
  338. $exists: false,
  339. },
  340. },
  341. {
  342. $set: {
  343. subtaskSort: -1,
  344. },
  345. },
  346. noValidateMulti,
  347. );
  348. });
  349. Migrations.add('add-subtasks-allowed', () => {
  350. Boards.update(
  351. {
  352. allowsSubtasks: {
  353. $exists: false,
  354. },
  355. },
  356. {
  357. $set: {
  358. allowsSubtasks: true,
  359. },
  360. },
  361. noValidateMulti,
  362. );
  363. });
  364. Migrations.add('add-subtasks-allowed', () => {
  365. Boards.update(
  366. {
  367. presentParentTask: {
  368. $exists: false,
  369. },
  370. },
  371. {
  372. $set: {
  373. presentParentTask: 'no-parent',
  374. },
  375. },
  376. noValidateMulti,
  377. );
  378. });
  379. Migrations.add('add-authenticationMethod', () => {
  380. Users.update(
  381. {
  382. authenticationMethod: {
  383. $exists: false,
  384. },
  385. },
  386. {
  387. $set: {
  388. authenticationMethod: 'password',
  389. },
  390. },
  391. noValidateMulti,
  392. );
  393. });
  394. Migrations.add('remove-tag', () => {
  395. Users.update(
  396. {},
  397. {
  398. $unset: {
  399. 'profile.tags': 1,
  400. },
  401. },
  402. noValidateMulti,
  403. );
  404. });
  405. Migrations.add('remove-customFields-references-broken', () => {
  406. Cards.update(
  407. { 'customFields.$value': null },
  408. {
  409. $pull: {
  410. customFields: { value: null },
  411. },
  412. },
  413. noValidateMulti,
  414. );
  415. });
  416. Migrations.add('add-product-name', () => {
  417. Settings.update(
  418. {
  419. productName: {
  420. $exists: false,
  421. },
  422. },
  423. {
  424. $set: {
  425. productName: '',
  426. },
  427. },
  428. noValidateMulti,
  429. );
  430. });
  431. Migrations.add('add-hide-logo', () => {
  432. Settings.update(
  433. {
  434. hideLogo: {
  435. $exists: false,
  436. },
  437. },
  438. {
  439. $set: {
  440. hideLogo: false,
  441. },
  442. },
  443. noValidateMulti,
  444. );
  445. });
  446. Migrations.add('add-displayAuthenticationMethod', () => {
  447. Settings.update(
  448. {
  449. displayAuthenticationMethod: {
  450. $exists: false,
  451. },
  452. },
  453. {
  454. $set: {
  455. displayAuthenticationMethod: true,
  456. },
  457. },
  458. noValidateMulti,
  459. );
  460. });
  461. Migrations.add('add-defaultAuthenticationMethod', () => {
  462. Settings.update(
  463. {
  464. defaultAuthenticationMethod: {
  465. $exists: false,
  466. },
  467. },
  468. {
  469. $set: {
  470. defaultAuthenticationMethod: 'password',
  471. },
  472. },
  473. noValidateMulti,
  474. );
  475. });
  476. Migrations.add('add-templates', () => {
  477. Boards.update(
  478. {
  479. type: {
  480. $exists: false,
  481. },
  482. },
  483. {
  484. $set: {
  485. type: 'board',
  486. },
  487. },
  488. noValidateMulti,
  489. );
  490. Swimlanes.update(
  491. {
  492. type: {
  493. $exists: false,
  494. },
  495. },
  496. {
  497. $set: {
  498. type: 'swimlane',
  499. },
  500. },
  501. noValidateMulti,
  502. );
  503. Lists.update(
  504. {
  505. type: {
  506. $exists: false,
  507. },
  508. swimlaneId: {
  509. $exists: false,
  510. },
  511. },
  512. {
  513. $set: {
  514. type: 'list',
  515. swimlaneId: '',
  516. },
  517. },
  518. noValidateMulti,
  519. );
  520. Users.find({
  521. 'profile.templatesBoardId': {
  522. $exists: false,
  523. },
  524. }).forEach(user => {
  525. // Create board and swimlanes
  526. Boards.insert(
  527. {
  528. title: TAPi18n.__('templates'),
  529. permission: 'private',
  530. type: 'template-container',
  531. members: [
  532. {
  533. userId: user._id,
  534. isAdmin: true,
  535. isActive: true,
  536. isNoComments: false,
  537. isCommentOnly: false,
  538. },
  539. ],
  540. },
  541. (err, boardId) => {
  542. // Insert the reference to our templates board
  543. Users.update(user._id, {
  544. $set: { 'profile.templatesBoardId': boardId },
  545. });
  546. // Insert the card templates swimlane
  547. Swimlanes.insert(
  548. {
  549. title: TAPi18n.__('card-templates-swimlane'),
  550. boardId,
  551. sort: 1,
  552. type: 'template-container',
  553. },
  554. (err, swimlaneId) => {
  555. // Insert the reference to out card templates swimlane
  556. Users.update(user._id, {
  557. $set: { 'profile.cardTemplatesSwimlaneId': swimlaneId },
  558. });
  559. },
  560. );
  561. // Insert the list templates swimlane
  562. Swimlanes.insert(
  563. {
  564. title: TAPi18n.__('list-templates-swimlane'),
  565. boardId,
  566. sort: 2,
  567. type: 'template-container',
  568. },
  569. (err, swimlaneId) => {
  570. // Insert the reference to out list templates swimlane
  571. Users.update(user._id, {
  572. $set: { 'profile.listTemplatesSwimlaneId': swimlaneId },
  573. });
  574. },
  575. );
  576. // Insert the board templates swimlane
  577. Swimlanes.insert(
  578. {
  579. title: TAPi18n.__('board-templates-swimlane'),
  580. boardId,
  581. sort: 3,
  582. type: 'template-container',
  583. },
  584. (err, swimlaneId) => {
  585. // Insert the reference to out board templates swimlane
  586. Users.update(user._id, {
  587. $set: { 'profile.boardTemplatesSwimlaneId': swimlaneId },
  588. });
  589. },
  590. );
  591. },
  592. );
  593. });
  594. });
  595. Migrations.add('fix-circular-reference_', () => {
  596. Cards.find().forEach(card => {
  597. if (card.parentId === card._id) {
  598. Cards.update(card._id, { $set: { parentId: '' } }, noValidateMulti);
  599. }
  600. });
  601. });
  602. Migrations.add('mutate-boardIds-in-customfields', () => {
  603. CustomFields.find().forEach(cf => {
  604. CustomFields.update(
  605. cf,
  606. {
  607. $set: {
  608. boardIds: [cf.boardId],
  609. },
  610. $unset: {
  611. boardId: '',
  612. },
  613. },
  614. noValidateMulti,
  615. );
  616. });
  617. });
  618. const modifiedAtTables = [
  619. AccountSettings,
  620. Actions,
  621. Activities,
  622. Announcements,
  623. Boards,
  624. CardComments,
  625. Cards,
  626. ChecklistItems,
  627. Checklists,
  628. CustomFields,
  629. Integrations,
  630. InvitationCodes,
  631. Lists,
  632. Rules,
  633. Settings,
  634. Swimlanes,
  635. Triggers,
  636. UnsavedEdits,
  637. Users,
  638. ];
  639. Migrations.add('add-missing-created-and-modified', () => {
  640. Promise.all(
  641. modifiedAtTables.map(db =>
  642. db
  643. .rawCollection()
  644. .update(
  645. { modifiedAt: { $exists: false } },
  646. { $set: { modifiedAt: new Date() } },
  647. { multi: true },
  648. )
  649. .then(() =>
  650. db
  651. .rawCollection()
  652. .update(
  653. { createdAt: { $exists: false } },
  654. { $set: { createdAt: new Date() } },
  655. { multi: true },
  656. ),
  657. ),
  658. ),
  659. )
  660. .then(() => {
  661. // eslint-disable-next-line no-console
  662. console.info('Successfully added createdAt and updatedAt to all tables');
  663. })
  664. .catch(e => {
  665. // eslint-disable-next-line no-console
  666. console.error(e);
  667. });
  668. });
  669. Migrations.add('fix-incorrect-dates', () => {
  670. const tables = [
  671. AccountSettings,
  672. Actions,
  673. Activities,
  674. Announcements,
  675. Boards,
  676. CardComments,
  677. Cards,
  678. ChecklistItems,
  679. Checklists,
  680. CustomFields,
  681. Integrations,
  682. InvitationCodes,
  683. Lists,
  684. Rules,
  685. Settings,
  686. Swimlanes,
  687. Triggers,
  688. UnsavedEdits,
  689. ];
  690. // Dates were previously created with Date.now() which is a number, not a date
  691. tables.forEach(t =>
  692. t
  693. .rawCollection()
  694. .find({ $or: [{ createdAt: { $type: 1 } }, { updatedAt: { $type: 1 } }] })
  695. .forEach(({ _id, createdAt, updatedAt }) => {
  696. t.rawCollection().update(
  697. { _id },
  698. {
  699. $set: {
  700. createdAt: new Date(createdAt),
  701. updatedAt: new Date(updatedAt),
  702. },
  703. },
  704. );
  705. }),
  706. );
  707. });
  708. Migrations.add('add-assignee', () => {
  709. Cards.update(
  710. {
  711. assignees: {
  712. $exists: false,
  713. },
  714. },
  715. {
  716. $set: {
  717. assignees: [],
  718. },
  719. },
  720. noValidateMulti,
  721. );
  722. });
  723. Migrations.add('add-profile-showDesktopDragHandles', () => {
  724. Users.update(
  725. {
  726. 'profile.showDesktopDragHandles': {
  727. $exists: false,
  728. },
  729. },
  730. {
  731. $set: {
  732. 'profile.showDesktopDragHandles': false,
  733. },
  734. },
  735. noValidateMulti,
  736. );
  737. });
  738. Migrations.add('add-profile-hiddenMinicardLabelText', () => {
  739. Users.update(
  740. {
  741. 'profile.hiddenMinicardLabelText': {
  742. $exists: false,
  743. },
  744. },
  745. {
  746. $set: {
  747. 'profile.hiddenMinicardLabelText': false,
  748. },
  749. },
  750. noValidateMulti,
  751. );
  752. });
  753. Migrations.add('add-receiveddate-allowed', () => {
  754. Boards.update(
  755. {
  756. allowsReceivedDate: {
  757. $exists: false,
  758. },
  759. },
  760. {
  761. $set: {
  762. allowsReceivedDate: true,
  763. },
  764. },
  765. noValidateMulti,
  766. );
  767. });
  768. Migrations.add('add-startdate-allowed', () => {
  769. Boards.update(
  770. {
  771. allowsStartDate: {
  772. $exists: false,
  773. },
  774. },
  775. {
  776. $set: {
  777. allowsStartDate: true,
  778. },
  779. },
  780. noValidateMulti,
  781. );
  782. });
  783. Migrations.add('add-duedate-allowed', () => {
  784. Boards.update(
  785. {
  786. allowsDueDate: {
  787. $exists: false,
  788. },
  789. },
  790. {
  791. $set: {
  792. allowsDueDate: true,
  793. },
  794. },
  795. noValidateMulti,
  796. );
  797. });
  798. Migrations.add('add-enddate-allowed', () => {
  799. Boards.update(
  800. {
  801. allowsEndDate: {
  802. $exists: false,
  803. },
  804. },
  805. {
  806. $set: {
  807. allowsEndDate: true,
  808. },
  809. },
  810. noValidateMulti,
  811. );
  812. });
  813. Migrations.add('add-members-allowed', () => {
  814. Boards.update(
  815. {
  816. allowsMembers: {
  817. $exists: false,
  818. },
  819. },
  820. {
  821. $set: {
  822. allowsMembers: true,
  823. },
  824. },
  825. noValidateMulti,
  826. );
  827. });
  828. Migrations.add('add-assignee-allowed', () => {
  829. Boards.update(
  830. {
  831. allowsAssignee: {
  832. $exists: false,
  833. },
  834. },
  835. {
  836. $set: {
  837. allowsAssignee: true,
  838. },
  839. },
  840. noValidateMulti,
  841. );
  842. });
  843. Migrations.add('add-labels-allowed', () => {
  844. Boards.update(
  845. {
  846. allowsLabels: {
  847. $exists: false,
  848. },
  849. },
  850. {
  851. $set: {
  852. allowsLabels: true,
  853. },
  854. },
  855. noValidateMulti,
  856. );
  857. });
  858. Migrations.add('add-checklists-allowed', () => {
  859. Boards.update(
  860. {
  861. allowsChecklists: {
  862. $exists: false,
  863. },
  864. },
  865. {
  866. $set: {
  867. allowsChecklists: true,
  868. },
  869. },
  870. noValidateMulti,
  871. );
  872. });
  873. Migrations.add('add-attachments-allowed', () => {
  874. Boards.update(
  875. {
  876. allowsAttachments: {
  877. $exists: false,
  878. },
  879. },
  880. {
  881. $set: {
  882. allowsAttachments: true,
  883. },
  884. },
  885. noValidateMulti,
  886. );
  887. });
  888. Migrations.add('add-comments-allowed', () => {
  889. Boards.update(
  890. {
  891. allowsComments: {
  892. $exists: false,
  893. },
  894. },
  895. {
  896. $set: {
  897. allowsComments: true,
  898. },
  899. },
  900. noValidateMulti,
  901. );
  902. });
  903. Migrations.add('add-assigned-by-allowed', () => {
  904. Boards.update(
  905. {
  906. allowsAssignedBy: {
  907. $exists: false,
  908. },
  909. },
  910. {
  911. $set: {
  912. allowsAssignedBy: true,
  913. },
  914. },
  915. noValidateMulti,
  916. );
  917. });
  918. Migrations.add('add-requested-by-allowed', () => {
  919. Boards.update(
  920. {
  921. allowsRequestedBy: {
  922. $exists: false,
  923. },
  924. },
  925. {
  926. $set: {
  927. allowsRequestedBy: true,
  928. },
  929. },
  930. noValidateMulti,
  931. );
  932. });
  933. Migrations.add('add-activities-allowed', () => {
  934. Boards.update(
  935. {
  936. allowsActivities: {
  937. $exists: false,
  938. },
  939. },
  940. {
  941. $set: {
  942. allowsActivities: true,
  943. },
  944. },
  945. noValidateMulti,
  946. );
  947. });
  948. Migrations.add('add-description-title-allowed', () => {
  949. Boards.update(
  950. {
  951. allowsDescriptionTitle: {
  952. $exists: false,
  953. },
  954. },
  955. {
  956. $set: {
  957. allowsDescriptionTitle: true,
  958. },
  959. },
  960. noValidateMulti,
  961. );
  962. });
  963. Migrations.add('add-description-text-allowed', () => {
  964. Boards.update(
  965. {
  966. allowsDescriptionText: {
  967. $exists: false,
  968. },
  969. },
  970. {
  971. $set: {
  972. allowsDescriptionText: true,
  973. },
  974. },
  975. noValidateMulti,
  976. );
  977. });
  978. Migrations.add('add-sort-field-to-boards', () => {
  979. Boards.find().forEach((board, index) => {
  980. if (!board.hasOwnProperty('sort')) {
  981. Boards.direct.update(board._id, { $set: { sort: index } }, noValidate);
  982. }
  983. });
  984. });