optirs_core/research/
collaboration.rs

1// Collaboration tools for multi-researcher projects
2//
3// This module provides tools for managing collaborative research projects,
4// including real-time editing, version control, communication, and task management.
5
6use crate::error::{OptimError, Result};
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::path::PathBuf;
11
12/// Collaborative workspace for research projects
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct CollaborativeWorkspace {
15    /// Workspace identifier
16    pub id: String,
17    /// Workspace name
18    pub name: String,
19    /// Project members
20    pub members: Vec<ProjectMember>,
21    /// Shared documents
22    pub documents: Vec<SharedDocument>,
23    /// Communication channels
24    pub channels: Vec<CommunicationChannel>,
25    /// Task assignments
26    pub tasks: Vec<Task>,
27    /// Version control information
28    pub version_control: VersionControl,
29    /// Workspace settings
30    pub settings: WorkspaceSettings,
31    /// Access control
32    pub access_control: AccessControl,
33    /// Activity log
34    pub activity_log: Vec<Activity>,
35    /// Creation timestamp
36    pub created_at: DateTime<Utc>,
37    /// Last modified timestamp
38    pub modified_at: DateTime<Utc>,
39}
40
41/// Project member information
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ProjectMember {
44    /// Member identifier
45    pub id: String,
46    /// User information
47    pub user: UserInfo,
48    /// Member role
49    pub role: MemberRole,
50    /// Permissions
51    pub permissions: Vec<Permission>,
52    /// Join date
53    pub joined_at: DateTime<Utc>,
54    /// Last active timestamp
55    pub last_active: DateTime<Utc>,
56    /// Member status
57    pub status: MemberStatus,
58    /// Contribution statistics
59    pub contributions: ContributionStats,
60}
61
62/// User information
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct UserInfo {
65    /// Full name
66    pub name: String,
67    /// Email address
68    pub email: String,
69    /// Institution
70    pub institution: String,
71    /// Profile picture URL
72    pub avatar_url: Option<String>,
73    /// Timezone
74    pub timezone: String,
75    /// Preferred language
76    pub language: String,
77    /// Research interests
78    pub research_interests: Vec<String>,
79}
80
81/// Member roles
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
83pub enum MemberRole {
84    /// Project owner
85    Owner,
86    /// Project administrator
87    Admin,
88    /// Principal investigator
89    PrincipalInvestigator,
90    /// Senior researcher
91    SeniorResearcher,
92    /// Researcher
93    Researcher,
94    /// PhD student
95    PhDStudent,
96    /// Masters student
97    MastersStudent,
98    /// Research assistant
99    ResearchAssistant,
100    /// Collaborator
101    Collaborator,
102    /// Guest
103    Guest,
104    /// Observer (read-only)
105    Observer,
106}
107
108/// Member permissions
109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
110pub enum Permission {
111    /// Read project data
112    Read,
113    /// Write/edit project data
114    Write,
115    /// Delete project data
116    Delete,
117    /// Manage members
118    ManageMembers,
119    /// Manage permissions
120    ManagePermissions,
121    /// Manage settings
122    ManageSettings,
123    /// Create experiments
124    CreateExperiments,
125    /// Run experiments
126    RunExperiments,
127    /// Publish results
128    PublishResults,
129    /// Access sensitive data
130    AccessSensitiveData,
131}
132
133/// Member status
134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
135pub enum MemberStatus {
136    /// Active member
137    Active,
138    /// Inactive member
139    Inactive,
140    /// On leave
141    OnLeave,
142    /// Suspended
143    Suspended,
144    /// Former member
145    Former,
146}
147
148/// Contribution statistics
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct ContributionStats {
151    /// Number of experiments created
152    pub experiments_created: usize,
153    /// Number of experiments run
154    pub experiments_run: usize,
155    /// Lines of code contributed
156    pub lines_of_code: usize,
157    /// Documents authored
158    pub documents_authored: usize,
159    /// Comments/discussions posted
160    pub comments_posted: usize,
161    /// Reviews conducted
162    pub reviews_conducted: usize,
163    /// Total contribution score
164    pub contribution_score: f64,
165}
166
167/// Shared document in the workspace
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct SharedDocument {
170    /// Document identifier
171    pub id: String,
172    /// Document name
173    pub name: String,
174    /// Document type
175    pub document_type: DocumentType,
176    /// Document content
177    pub content: String,
178    /// Document owner
179    pub owner_id: String,
180    /// Collaborators with edit access
181    pub collaborators: Vec<String>,
182    /// Document version
183    pub version: u32,
184    /// Version history
185    pub version_history: Vec<DocumentVersion>,
186    /// Access permissions
187    pub access_permissions: DocumentPermissions,
188    /// Document metadata
189    pub metadata: DocumentMetadata,
190    /// Creation timestamp
191    pub created_at: DateTime<Utc>,
192    /// Last modified timestamp
193    pub modified_at: DateTime<Utc>,
194}
195
196/// Document types
197#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
198pub enum DocumentType {
199    /// Research paper/manuscript
200    Manuscript,
201    /// Experiment notes
202    ExperimentNotes,
203    /// Meeting notes
204    MeetingNotes,
205    /// Literature review
206    LiteratureReview,
207    /// Research proposal
208    ResearchProposal,
209    /// Data analysis
210    DataAnalysis,
211    /// Code documentation
212    CodeDocumentation,
213    /// Presentation
214    Presentation,
215    /// Other document
216    Other(String),
217}
218
219/// Document version
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct DocumentVersion {
222    /// Version number
223    pub version: u32,
224    /// Version author
225    pub author_id: String,
226    /// Version content
227    pub content: String,
228    /// Change summary
229    pub change_summary: String,
230    /// Timestamp
231    pub timestamp: DateTime<Utc>,
232    /// Content hash for integrity
233    pub content_hash: String,
234}
235
236/// Document permissions
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct DocumentPermissions {
239    /// Public visibility
240    pub public: bool,
241    /// Read access
242    pub read_access: Vec<String>,
243    /// Write access
244    pub write_access: Vec<String>,
245    /// Admin access
246    pub admin_access: Vec<String>,
247}
248
249/// Document metadata
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct DocumentMetadata {
252    /// Document tags
253    pub tags: Vec<String>,
254    /// Word count
255    pub word_count: usize,
256    /// Character count
257    pub character_count: usize,
258    /// Number of collaborators
259    pub collaborator_count: usize,
260    /// Number of versions
261    pub version_count: usize,
262    /// Last editor
263    pub last_editor_id: String,
264}
265
266/// Communication channel
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct CommunicationChannel {
269    /// Channel identifier
270    pub id: String,
271    /// Channel name
272    pub name: String,
273    /// Channel description
274    pub description: String,
275    /// Channel type
276    pub channel_type: ChannelType,
277    /// Channel members
278    pub members: Vec<String>,
279    /// Messages in the channel
280    pub messages: Vec<Message>,
281    /// Channel settings
282    pub settings: ChannelSettings,
283    /// Creation timestamp
284    pub created_at: DateTime<Utc>,
285}
286
287/// Channel types
288#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
289pub enum ChannelType {
290    /// General discussion
291    General,
292    /// Experiment discussion
293    Experiments,
294    /// Paper writing
295    PaperWriting,
296    /// Code review
297    CodeReview,
298    /// Announcements
299    Announcements,
300    /// Random/off-topic
301    Random,
302    /// Private channel
303    Private,
304    /// Direct message
305    DirectMessage,
306}
307
308/// Message in a communication channel
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct Message {
311    /// Message identifier
312    pub id: String,
313    /// Message author
314    pub author_id: String,
315    /// Message content
316    pub content: String,
317    /// Message type
318    pub message_type: MessageType,
319    /// Attachments
320    pub attachments: Vec<Attachment>,
321    /// Replies to this message
322    pub replies: Vec<Message>,
323    /// Reactions
324    pub reactions: Vec<Reaction>,
325    /// Mentions
326    pub mentions: Vec<String>,
327    /// Thread ID (if part of a thread)
328    pub thread_id: Option<String>,
329    /// Timestamp
330    pub timestamp: DateTime<Utc>,
331    /// Edit history
332    pub edit_history: Vec<MessageEdit>,
333}
334
335/// Message types
336#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
337pub enum MessageType {
338    /// Regular text message
339    Text,
340    /// Code snippet
341    Code,
342    /// File attachment
343    File,
344    /// System message
345    System,
346    /// Experiment result
347    ExperimentResult,
348    /// Task assignment
349    TaskAssignment,
350    /// Meeting invitation
351    MeetingInvitation,
352}
353
354/// File attachment
355#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct Attachment {
357    /// File name
358    pub filename: String,
359    /// File size in bytes
360    pub size: usize,
361    /// MIME type
362    pub mime_type: String,
363    /// File path or URL
364    pub file_path: String,
365    /// File hash for integrity
366    pub file_hash: String,
367    /// Upload timestamp
368    pub uploaded_at: DateTime<Utc>,
369}
370
371/// Message reaction
372#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct Reaction {
374    /// Emoji or reaction type
375    pub emoji: String,
376    /// Users who reacted
377    pub users: Vec<String>,
378    /// Reaction count
379    pub count: usize,
380}
381
382/// Message edit history
383#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct MessageEdit {
385    /// Original content
386    pub original_content: String,
387    /// Edit timestamp
388    pub edited_at: DateTime<Utc>,
389    /// Edit reason
390    pub edit_reason: Option<String>,
391}
392
393/// Channel settings
394#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct ChannelSettings {
396    /// Notifications enabled
397    pub notifications: bool,
398    /// Archive old messages
399    pub auto_archive: bool,
400    /// Archive threshold (days)
401    pub archive_after_days: u32,
402    /// Allow external invites
403    pub allow_external_invites: bool,
404    /// Moderation settings
405    pub moderation: ModerationSettings,
406}
407
408/// Moderation settings
409#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct ModerationSettings {
411    /// Require approval for new messages
412    pub require_approval: bool,
413    /// Auto-delete inappropriate content
414    pub auto_delete_inappropriate: bool,
415    /// Spam filtering enabled
416    pub spam_filtering: bool,
417    /// Moderators
418    pub moderators: Vec<String>,
419}
420
421/// Task in the collaborative workspace
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct Task {
424    /// Task identifier
425    pub id: String,
426    /// Task title
427    pub title: String,
428    /// Task description
429    pub description: String,
430    /// Task type
431    pub task_type: TaskType,
432    /// Task status
433    pub status: TaskStatus,
434    /// Task priority
435    pub priority: TaskPriority,
436    /// Assigned to
437    pub assigned_to: Vec<String>,
438    /// Created by
439    pub created_by: String,
440    /// Due date
441    pub due_date: Option<DateTime<Utc>>,
442    /// Estimated effort (hours)
443    pub estimated_hours: Option<f64>,
444    /// Actual effort (hours)
445    pub actual_hours: Option<f64>,
446    /// Task dependencies
447    pub dependencies: Vec<String>,
448    /// Subtasks
449    pub subtasks: Vec<Task>,
450    /// Comments
451    pub comments: Vec<TaskComment>,
452    /// Attachments
453    pub attachments: Vec<Attachment>,
454    /// Labels/tags
455    pub labels: Vec<String>,
456    /// Creation timestamp
457    pub created_at: DateTime<Utc>,
458    /// Completion timestamp
459    pub completed_at: Option<DateTime<Utc>>,
460}
461
462/// Task types
463#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
464pub enum TaskType {
465    /// Experiment design
466    ExperimentDesign,
467    /// Data collection
468    DataCollection,
469    /// Data analysis
470    DataAnalysis,
471    /// Code development
472    CodeDevelopment,
473    /// Documentation
474    Documentation,
475    /// Literature review
476    LiteratureReview,
477    /// Paper writing
478    PaperWriting,
479    /// Review/feedback
480    Review,
481    /// Meeting
482    Meeting,
483    /// Administrative
484    Administrative,
485    /// Other
486    Other(String),
487}
488
489/// Task status
490#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
491pub enum TaskStatus {
492    /// Task not started
493    NotStarted,
494    /// Task in progress
495    InProgress,
496    /// Task on hold
497    OnHold,
498    /// Task completed
499    Completed,
500    /// Task cancelled
501    Cancelled,
502    /// Task needs review
503    NeedsReview,
504    /// Task approved
505    Approved,
506}
507
508/// Task priority
509#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
510pub enum TaskPriority {
511    /// Critical priority
512    Critical,
513    /// High priority
514    High,
515    /// Medium priority
516    Medium,
517    /// Low priority
518    Low,
519}
520
521/// Task comment
522#[derive(Debug, Clone, Serialize, Deserialize)]
523pub struct TaskComment {
524    /// Comment ID
525    pub id: String,
526    /// Comment author
527    pub author_id: String,
528    /// Comment content
529    pub content: String,
530    /// Timestamp
531    pub timestamp: DateTime<Utc>,
532}
533
534/// Version control system for the workspace
535#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct VersionControl {
537    /// Repository URL
538    pub repository_url: Option<String>,
539    /// Current branch
540    pub current_branch: String,
541    /// Available branches
542    pub branches: Vec<String>,
543    /// Commit history
544    pub commits: Vec<Commit>,
545    /// Merge requests
546    pub merge_requests: Vec<MergeRequest>,
547    /// Version control settings
548    pub settings: VersionControlSettings,
549}
550
551/// Git commit information
552#[derive(Debug, Clone, Serialize, Deserialize)]
553pub struct Commit {
554    /// Commit hash
555    pub hash: String,
556    /// Commit author
557    pub author: String,
558    /// Commit message
559    pub message: String,
560    /// Commit timestamp
561    pub timestamp: DateTime<Utc>,
562    /// Modified files
563    pub modified_files: Vec<String>,
564    /// Parent commits
565    pub parents: Vec<String>,
566}
567
568/// Merge/Pull request
569#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct MergeRequest {
571    /// Request ID
572    pub id: String,
573    /// Request title
574    pub title: String,
575    /// Request description
576    pub description: String,
577    /// Source branch
578    pub source_branch: String,
579    /// Target branch
580    pub target_branch: String,
581    /// Request author
582    pub author: String,
583    /// Reviewers
584    pub reviewers: Vec<String>,
585    /// Request status
586    pub status: MergeRequestStatus,
587    /// Creation timestamp
588    pub created_at: DateTime<Utc>,
589    /// Merge timestamp
590    pub merged_at: Option<DateTime<Utc>>,
591}
592
593/// Merge request status
594#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
595pub enum MergeRequestStatus {
596    /// Open for review
597    Open,
598    /// Under review
599    UnderReview,
600    /// Approved
601    Approved,
602    /// Merged
603    Merged,
604    /// Closed without merging
605    Closed,
606    /// Draft
607    Draft,
608}
609
610/// Version control settings
611#[derive(Debug, Clone, Serialize, Deserialize)]
612pub struct VersionControlSettings {
613    /// Auto-commit enabled
614    pub auto_commit: bool,
615    /// Auto-commit frequency (minutes)
616    pub auto_commit_frequency: u32,
617    /// Require review for merges
618    pub require_review: bool,
619    /// Protected branches
620    pub protected_branches: Vec<String>,
621    /// Automatic backups
622    pub automatic_backups: bool,
623}
624
625/// Workspace settings
626#[derive(Debug, Clone, Serialize, Deserialize)]
627pub struct WorkspaceSettings {
628    /// Workspace timezone
629    pub timezone: String,
630    /// Default language
631    pub default_language: String,
632    /// Collaboration settings
633    pub collaboration: CollaborationSettings,
634    /// Notification settings
635    pub notifications: NotificationSettings,
636    /// Integration settings
637    pub integrations: IntegrationSettings,
638}
639
640/// Collaboration settings
641#[derive(Debug, Clone, Serialize, Deserialize)]
642pub struct CollaborationSettings {
643    /// Real-time editing enabled
644    pub real_time_editing: bool,
645    /// Auto-save frequency (seconds)
646    pub auto_save_frequency: u32,
647    /// Conflict resolution strategy
648    pub conflict_resolution: ConflictResolution,
649    /// Maximum simultaneous editors
650    pub max_simultaneous_editors: u32,
651}
652
653/// Conflict resolution strategies
654#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
655pub enum ConflictResolution {
656    /// Manual resolution required
657    Manual,
658    /// Last writer wins
659    LastWriterWins,
660    /// First writer wins
661    FirstWriterWins,
662    /// Merge changes
663    Merge,
664}
665
666/// Notification settings
667#[derive(Debug, Clone, Serialize, Deserialize)]
668pub struct NotificationSettings {
669    /// Email notifications
670    pub email: bool,
671    /// In-app notifications
672    pub in_app: bool,
673    /// Desktop notifications
674    pub desktop: bool,
675    /// Mobile push notifications
676    pub mobile_push: bool,
677    /// Notification frequency
678    pub frequency: NotificationFrequency,
679}
680
681/// Notification frequency
682#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
683pub enum NotificationFrequency {
684    /// Immediate notifications
685    Immediate,
686    /// Digest every hour
687    Hourly,
688    /// Daily digest
689    Daily,
690    /// Weekly digest
691    Weekly,
692    /// No notifications
693    None,
694}
695
696/// Integration settings
697#[derive(Debug, Clone, Serialize, Deserialize, Default)]
698pub struct IntegrationSettings {
699    /// Slack integration
700    pub slack: Option<SlackIntegration>,
701    /// Email integration
702    pub email: Option<EmailIntegration>,
703    /// Calendar integration
704    pub calendar: Option<CalendarIntegration>,
705    /// Cloud storage integration
706    pub cloud_storage: Option<CloudStorageIntegration>,
707}
708
709/// Slack integration
710#[derive(Debug, Clone, Serialize, Deserialize)]
711pub struct SlackIntegration {
712    /// Webhook URL
713    pub webhook_url: String,
714    /// Default channel
715    pub default_channel: String,
716    /// Enable experiment notifications
717    pub experiment_notifications: bool,
718    /// Enable task notifications
719    pub task_notifications: bool,
720}
721
722/// Email integration
723#[derive(Debug, Clone, Serialize, Deserialize)]
724pub struct EmailIntegration {
725    /// SMTP server
726    pub smtp_server: String,
727    /// SMTP port
728    pub smtp_port: u16,
729    /// Email address
730    pub email_address: String,
731    /// Authentication credentials
732    pub auth_credentials: Option<String>,
733}
734
735/// Calendar integration
736#[derive(Debug, Clone, Serialize, Deserialize)]
737pub struct CalendarIntegration {
738    /// Calendar provider
739    pub provider: CalendarProvider,
740    /// Calendar ID
741    pub calendar_id: String,
742    /// Sync meetings
743    pub sync_meetings: bool,
744    /// Sync deadlines
745    pub sync_deadlines: bool,
746}
747
748/// Calendar providers
749#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
750pub enum CalendarProvider {
751    /// Google Calendar
752    Google,
753    /// Outlook Calendar
754    Outlook,
755    /// Apple Calendar
756    Apple,
757    /// CalDAV
758    CalDAV,
759}
760
761/// Cloud storage integration
762#[derive(Debug, Clone, Serialize, Deserialize)]
763pub struct CloudStorageIntegration {
764    /// Storage provider
765    pub provider: CloudStorageProvider,
766    /// Storage path
767    pub storage_path: String,
768    /// Auto-sync enabled
769    pub auto_sync: bool,
770    /// Sync frequency (minutes)
771    pub sync_frequency: u32,
772}
773
774/// Cloud storage providers
775#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
776pub enum CloudStorageProvider {
777    /// Google Drive
778    GoogleDrive,
779    /// Dropbox
780    Dropbox,
781    /// OneDrive
782    OneDrive,
783    /// Amazon S3
784    AmazonS3,
785    /// Custom provider
786    Custom(String),
787}
788
789/// Access control for the workspace
790#[derive(Debug, Clone, Serialize, Deserialize)]
791pub struct AccessControl {
792    /// Access control lists
793    pub acls: Vec<AccessControlEntry>,
794    /// Default permissions for new members
795    pub default_permissions: Vec<Permission>,
796    /// Guest access allowed
797    pub guest_access: bool,
798    /// Public visibility
799    pub public_visibility: bool,
800    /// Invitation settings
801    pub invitation_settings: InvitationSettings,
802}
803
804/// Access control entry
805#[derive(Debug, Clone, Serialize, Deserialize)]
806pub struct AccessControlEntry {
807    /// Principal (user, group, or role)
808    pub principal: Principal,
809    /// Granted permissions
810    pub permissions: Vec<Permission>,
811    /// Access expiration
812    pub expires_at: Option<DateTime<Utc>>,
813}
814
815/// Principal (user, group, or role)
816#[derive(Debug, Clone, Serialize, Deserialize)]
817pub enum Principal {
818    /// Individual user
819    User(String),
820    /// User group
821    Group(String),
822    /// Member role
823    Role(MemberRole),
824    /// Everyone
825    Everyone,
826}
827
828/// Invitation settings
829#[derive(Debug, Clone, Serialize, Deserialize)]
830pub struct InvitationSettings {
831    /// Require approval for invitations
832    pub require_approval: bool,
833    /// Allow external invitations
834    pub allow_external: bool,
835    /// Invitation expiration (days)
836    pub expiration_days: u32,
837    /// Maximum invitations per user
838    pub max_invitations_per_user: u32,
839}
840
841/// Activity log entry
842#[derive(Debug, Clone, Serialize, Deserialize)]
843pub struct Activity {
844    /// Activity ID
845    pub id: String,
846    /// User who performed the activity
847    pub user_id: String,
848    /// Activity type
849    pub activity_type: ActivityType,
850    /// Activity description
851    pub description: String,
852    /// Affected resources
853    pub resources: Vec<String>,
854    /// Activity metadata
855    pub metadata: HashMap<String, serde_json::Value>,
856    /// Timestamp
857    pub timestamp: DateTime<Utc>,
858}
859
860/// Activity types
861#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
862pub enum ActivityType {
863    /// User joined workspace
864    UserJoined,
865    /// User left workspace
866    UserLeft,
867    /// Document created
868    DocumentCreated,
869    /// Document edited
870    DocumentEdited,
871    /// Document deleted
872    DocumentDeleted,
873    /// Experiment created
874    ExperimentCreated,
875    /// Experiment started
876    ExperimentStarted,
877    /// Experiment completed
878    ExperimentCompleted,
879    /// Task created
880    TaskCreated,
881    /// Task assigned
882    TaskAssigned,
883    /// Task completed
884    TaskCompleted,
885    /// Message posted
886    MessagePosted,
887    /// File uploaded
888    FileUploaded,
889    /// Merge request created
890    MergeRequestCreated,
891    /// Settings changed
892    SettingsChanged,
893}
894
895/// Collaboration manager
896#[derive(Debug)]
897pub struct CollaborationManager {
898    /// Active workspaces
899    workspaces: HashMap<String, CollaborativeWorkspace>,
900    /// Storage directory
901    storage_dir: PathBuf,
902    /// Manager settings
903    settings: CollaborationManagerSettings,
904}
905
906/// Manager settings
907#[derive(Debug, Clone, Serialize, Deserialize)]
908pub struct CollaborationManagerSettings {
909    /// Maximum workspaces per user
910    pub max_workspaces_per_user: u32,
911    /// Default workspace settings
912    pub default_workspace_settings: WorkspaceSettings,
913    /// Backup settings
914    pub backup_settings: BackupSettings,
915}
916
917/// Backup settings
918#[derive(Debug, Clone, Serialize, Deserialize)]
919pub struct BackupSettings {
920    /// Backup enabled
921    pub enabled: bool,
922    /// Backup frequency (hours)
923    pub frequency_hours: u32,
924    /// Backup retention (days)
925    pub retention_days: u32,
926    /// Backup location
927    pub backup_location: PathBuf,
928}
929
930impl CollaborativeWorkspace {
931    /// Create a new collaborative workspace
932    pub fn new(name: &str, owner: UserInfo) -> Self {
933        let now = Utc::now();
934        let workspace_id = uuid::Uuid::new_v4().to_string();
935        let owner_id = uuid::Uuid::new_v4().to_string();
936
937        let owner_member = ProjectMember {
938            id: owner_id.clone(),
939            user: owner,
940            role: MemberRole::Owner,
941            permissions: vec![
942                Permission::Read,
943                Permission::Write,
944                Permission::Delete,
945                Permission::ManageMembers,
946                Permission::ManagePermissions,
947                Permission::ManageSettings,
948                Permission::CreateExperiments,
949                Permission::RunExperiments,
950                Permission::PublishResults,
951                Permission::AccessSensitiveData,
952            ],
953            joined_at: now,
954            last_active: now,
955            status: MemberStatus::Active,
956            contributions: ContributionStats::default(),
957        };
958
959        Self {
960            id: workspace_id,
961            name: name.to_string(),
962            members: vec![owner_member],
963            documents: Vec::new(),
964            channels: Vec::new(),
965            tasks: Vec::new(),
966            version_control: VersionControl::default(),
967            settings: WorkspaceSettings::default(),
968            access_control: AccessControl::default(),
969            activity_log: Vec::new(),
970            created_at: now,
971            modified_at: now,
972        }
973    }
974
975    /// Add a member to the workspace
976    pub fn add_member(&mut self, user: UserInfo, role: MemberRole) -> Result<()> {
977        let member_id = uuid::Uuid::new_v4().to_string();
978        let permissions = self.get_default_permissions_for_role(&role);
979
980        let member = ProjectMember {
981            id: member_id.clone(),
982            user,
983            role,
984            permissions,
985            joined_at: Utc::now(),
986            last_active: Utc::now(),
987            status: MemberStatus::Active,
988            contributions: ContributionStats::default(),
989        };
990
991        self.members.push(member);
992        self.log_activity(
993            &member_id,
994            ActivityType::UserJoined,
995            "User joined the workspace".to_string(),
996            vec![],
997        );
998
999        Ok(())
1000    }
1001
1002    /// Create a shared document
1003    pub fn create_document(
1004        &mut self,
1005        name: &str,
1006        document_type: DocumentType,
1007        ownerid: &str,
1008    ) -> Result<String> {
1009        if !self.has_permission(ownerid, &Permission::Write) {
1010            return Err(OptimError::InvalidConfig(
1011                "Insufficient permissions to create document".to_string(),
1012            ));
1013        }
1014
1015        let document_id = uuid::Uuid::new_v4().to_string();
1016        let document = SharedDocument {
1017            id: document_id.clone(),
1018            name: name.to_string(),
1019            document_type,
1020            content: String::new(),
1021            owner_id: ownerid.to_string(),
1022            collaborators: Vec::new(),
1023            version: 1,
1024            version_history: Vec::new(),
1025            access_permissions: DocumentPermissions {
1026                public: false,
1027                read_access: self.members.iter().map(|m| m.id.clone()).collect(),
1028                write_access: vec![ownerid.to_string()],
1029                admin_access: vec![ownerid.to_string()],
1030            },
1031            metadata: DocumentMetadata {
1032                tags: Vec::new(),
1033                word_count: 0,
1034                character_count: 0,
1035                collaborator_count: 1,
1036                version_count: 1,
1037                last_editor_id: ownerid.to_string(),
1038            },
1039            created_at: Utc::now(),
1040            modified_at: Utc::now(),
1041        };
1042
1043        self.documents.push(document);
1044        self.log_activity(
1045            ownerid,
1046            ActivityType::DocumentCreated,
1047            format!("Created document: {name}"),
1048            vec![document_id.clone()],
1049        );
1050
1051        Ok(document_id)
1052    }
1053
1054    /// Create a communication channel
1055    pub fn create_channel(
1056        &mut self,
1057        name: &str,
1058        channel_type: ChannelType,
1059        creatorid: &str,
1060    ) -> Result<String> {
1061        let channel_id = uuid::Uuid::new_v4().to_string();
1062        let channel = CommunicationChannel {
1063            id: channel_id.clone(),
1064            name: name.to_string(),
1065            description: String::new(),
1066            channel_type,
1067            members: self.members.iter().map(|m| m.id.clone()).collect(),
1068            messages: Vec::new(),
1069            settings: ChannelSettings::default(),
1070            created_at: Utc::now(),
1071        };
1072
1073        self.channels.push(channel);
1074        Ok(channel_id)
1075    }
1076
1077    /// Create a task
1078    pub fn create_task(
1079        &mut self,
1080        title: &str,
1081        task_type: TaskType,
1082        creatorid: &str,
1083    ) -> Result<String> {
1084        let task_id = uuid::Uuid::new_v4().to_string();
1085        let task = Task {
1086            id: task_id.clone(),
1087            title: title.to_string(),
1088            description: String::new(),
1089            task_type,
1090            status: TaskStatus::NotStarted,
1091            priority: TaskPriority::Medium,
1092            assigned_to: Vec::new(),
1093            created_by: creatorid.to_string(),
1094            due_date: None,
1095            estimated_hours: None,
1096            actual_hours: None,
1097            dependencies: Vec::new(),
1098            subtasks: Vec::new(),
1099            comments: Vec::new(),
1100            attachments: Vec::new(),
1101            labels: Vec::new(),
1102            created_at: Utc::now(),
1103            completed_at: None,
1104        };
1105
1106        self.tasks.push(task);
1107        self.log_activity(
1108            creatorid,
1109            ActivityType::TaskCreated,
1110            format!("Created task: {title}"),
1111            vec![task_id.clone()],
1112        );
1113
1114        Ok(task_id)
1115    }
1116
1117    /// Check if a user has a specific permission
1118    pub fn has_permission(&self, userid: &str, permission: &Permission) -> bool {
1119        if let Some(member) = self.members.iter().find(|m| m.id == userid) {
1120            member.permissions.contains(permission)
1121        } else {
1122            false
1123        }
1124    }
1125
1126    /// Log an activity
1127    pub fn log_activity(
1128        &mut self,
1129        user_id: &str,
1130        activitytype: ActivityType,
1131        description: String,
1132        resources: Vec<String>,
1133    ) {
1134        let activity = Activity {
1135            id: uuid::Uuid::new_v4().to_string(),
1136            user_id: user_id.to_string(),
1137            activity_type: activitytype,
1138            description,
1139            resources,
1140            metadata: HashMap::new(),
1141            timestamp: Utc::now(),
1142        };
1143
1144        self.activity_log.push(activity);
1145        self.modified_at = Utc::now();
1146    }
1147
1148    fn get_default_permissions_for_role(&self, role: &MemberRole) -> Vec<Permission> {
1149        match role {
1150            MemberRole::Owner | MemberRole::Admin => vec![
1151                Permission::Read,
1152                Permission::Write,
1153                Permission::Delete,
1154                Permission::ManageMembers,
1155                Permission::ManagePermissions,
1156                Permission::ManageSettings,
1157                Permission::CreateExperiments,
1158                Permission::RunExperiments,
1159                Permission::PublishResults,
1160                Permission::AccessSensitiveData,
1161            ],
1162            MemberRole::PrincipalInvestigator | MemberRole::SeniorResearcher => vec![
1163                Permission::Read,
1164                Permission::Write,
1165                Permission::CreateExperiments,
1166                Permission::RunExperiments,
1167                Permission::PublishResults,
1168                Permission::AccessSensitiveData,
1169            ],
1170            MemberRole::Researcher | MemberRole::PhDStudent => vec![
1171                Permission::Read,
1172                Permission::Write,
1173                Permission::CreateExperiments,
1174                Permission::RunExperiments,
1175            ],
1176            MemberRole::MastersStudent | MemberRole::ResearchAssistant => vec![
1177                Permission::Read,
1178                Permission::Write,
1179                Permission::CreateExperiments,
1180            ],
1181            MemberRole::Collaborator => vec![Permission::Read, Permission::Write],
1182            MemberRole::Guest | MemberRole::Observer => vec![Permission::Read],
1183        }
1184    }
1185
1186    /// Generate workspace statistics
1187    pub fn generate_statistics(&self) -> WorkspaceStatistics {
1188        let active_members = self
1189            .members
1190            .iter()
1191            .filter(|m| m.status == MemberStatus::Active)
1192            .count();
1193
1194        let total_documents = self.documents.len();
1195        let total_tasks = self.tasks.len();
1196        let completed_tasks = self
1197            .tasks
1198            .iter()
1199            .filter(|t| t.status == TaskStatus::Completed)
1200            .count();
1201
1202        let total_messages = self.channels.iter().map(|c| c.messages.len()).sum();
1203
1204        let activity_last_30_days = self
1205            .activity_log
1206            .iter()
1207            .filter(|a| {
1208                let thirty_days_ago = Utc::now() - chrono::Duration::days(30);
1209                a.timestamp > thirty_days_ago
1210            })
1211            .count();
1212
1213        WorkspaceStatistics {
1214            total_members: self.members.len(),
1215            active_members,
1216            total_documents,
1217            total_tasks,
1218            completed_tasks,
1219            task_completion_rate: if total_tasks > 0 {
1220                completed_tasks as f64 / total_tasks as f64
1221            } else {
1222                0.0
1223            },
1224            total_messages,
1225            total_channels: self.channels.len(),
1226            activity_last_30_days,
1227            creation_date: self.created_at,
1228            last_activity: self.modified_at,
1229        }
1230    }
1231}
1232
1233/// Workspace statistics
1234#[derive(Debug, Clone, Serialize, Deserialize)]
1235pub struct WorkspaceStatistics {
1236    /// Total number of members
1237    pub total_members: usize,
1238    /// Number of active members
1239    pub active_members: usize,
1240    /// Total number of documents
1241    pub total_documents: usize,
1242    /// Total number of tasks
1243    pub total_tasks: usize,
1244    /// Number of completed tasks
1245    pub completed_tasks: usize,
1246    /// Task completion rate (0.0 to 1.0)
1247    pub task_completion_rate: f64,
1248    /// Total number of messages
1249    pub total_messages: usize,
1250    /// Total number of channels
1251    pub total_channels: usize,
1252    /// Activity count in last 30 days
1253    pub activity_last_30_days: usize,
1254    /// Workspace creation date
1255    pub creation_date: DateTime<Utc>,
1256    /// Last activity timestamp
1257    pub last_activity: DateTime<Utc>,
1258}
1259
1260impl Default for ContributionStats {
1261    fn default() -> Self {
1262        Self {
1263            experiments_created: 0,
1264            experiments_run: 0,
1265            lines_of_code: 0,
1266            documents_authored: 0,
1267            comments_posted: 0,
1268            reviews_conducted: 0,
1269            contribution_score: 0.0,
1270        }
1271    }
1272}
1273
1274impl Default for VersionControl {
1275    fn default() -> Self {
1276        Self {
1277            repository_url: None,
1278            current_branch: "main".to_string(),
1279            branches: vec!["main".to_string()],
1280            commits: Vec::new(),
1281            merge_requests: Vec::new(),
1282            settings: VersionControlSettings::default(),
1283        }
1284    }
1285}
1286
1287impl Default for VersionControlSettings {
1288    fn default() -> Self {
1289        Self {
1290            auto_commit: false,
1291            auto_commit_frequency: 60, // 1 hour
1292            require_review: true,
1293            protected_branches: vec!["main".to_string(), "master".to_string()],
1294            automatic_backups: true,
1295        }
1296    }
1297}
1298
1299impl Default for WorkspaceSettings {
1300    fn default() -> Self {
1301        Self {
1302            timezone: "UTC".to_string(),
1303            default_language: "en".to_string(),
1304            collaboration: CollaborationSettings::default(),
1305            notifications: NotificationSettings::default(),
1306            integrations: IntegrationSettings::default(),
1307        }
1308    }
1309}
1310
1311impl Default for CollaborationSettings {
1312    fn default() -> Self {
1313        Self {
1314            real_time_editing: true,
1315            auto_save_frequency: 30, // 30 seconds
1316            conflict_resolution: ConflictResolution::Manual,
1317            max_simultaneous_editors: 10,
1318        }
1319    }
1320}
1321
1322impl Default for NotificationSettings {
1323    fn default() -> Self {
1324        Self {
1325            email: true,
1326            in_app: true,
1327            desktop: false,
1328            mobile_push: false,
1329            frequency: NotificationFrequency::Daily,
1330        }
1331    }
1332}
1333
1334impl Default for AccessControl {
1335    fn default() -> Self {
1336        Self {
1337            acls: Vec::new(),
1338            default_permissions: vec![Permission::Read],
1339            guest_access: false,
1340            public_visibility: false,
1341            invitation_settings: InvitationSettings::default(),
1342        }
1343    }
1344}
1345
1346impl Default for InvitationSettings {
1347    fn default() -> Self {
1348        Self {
1349            require_approval: true,
1350            allow_external: false,
1351            expiration_days: 7,
1352            max_invitations_per_user: 10,
1353        }
1354    }
1355}
1356
1357impl Default for ChannelSettings {
1358    fn default() -> Self {
1359        Self {
1360            notifications: true,
1361            auto_archive: false,
1362            archive_after_days: 365,
1363            allow_external_invites: false,
1364            moderation: ModerationSettings::default(),
1365        }
1366    }
1367}
1368
1369impl Default for ModerationSettings {
1370    fn default() -> Self {
1371        Self {
1372            require_approval: false,
1373            auto_delete_inappropriate: false,
1374            spam_filtering: true,
1375            moderators: Vec::new(),
1376        }
1377    }
1378}
1379
1380#[cfg(test)]
1381mod tests {
1382    use super::*;
1383
1384    #[test]
1385    fn test_workspace_creation() {
1386        let owner = UserInfo {
1387            name: "Dr. Test".to_string(),
1388            email: "test@example.com".to_string(),
1389            institution: "Test University".to_string(),
1390            avatar_url: None,
1391            timezone: "UTC".to_string(),
1392            language: "en".to_string(),
1393            research_interests: vec!["machine learning".to_string()],
1394        };
1395
1396        let workspace = CollaborativeWorkspace::new("Test Workspace", owner);
1397
1398        assert_eq!(workspace.name, "Test Workspace");
1399        assert_eq!(workspace.members.len(), 1);
1400        assert_eq!(workspace.members[0].role, MemberRole::Owner);
1401        assert!(workspace.members[0]
1402            .permissions
1403            .contains(&Permission::ManageMembers));
1404    }
1405
1406    #[test]
1407    fn test_document_creation() {
1408        let owner = UserInfo {
1409            name: "Dr. Test".to_string(),
1410            email: "test@example.com".to_string(),
1411            institution: "Test University".to_string(),
1412            avatar_url: None,
1413            timezone: "UTC".to_string(),
1414            language: "en".to_string(),
1415            research_interests: vec![],
1416        };
1417
1418        let mut workspace = CollaborativeWorkspace::new("Test Workspace", owner);
1419        let owner_id = workspace.members[0].id.clone();
1420
1421        let doc_id = workspace
1422            .create_document("Test Document", DocumentType::Manuscript, &owner_id)
1423            .unwrap();
1424
1425        assert_eq!(workspace.documents.len(), 1);
1426        assert_eq!(workspace.documents[0].name, "Test Document");
1427        assert_eq!(
1428            workspace.documents[0].document_type,
1429            DocumentType::Manuscript
1430        );
1431        assert_eq!(workspace.activity_log.len(), 1);
1432        assert_eq!(
1433            workspace.activity_log[0].activity_type,
1434            ActivityType::DocumentCreated
1435        );
1436    }
1437
1438    #[test]
1439    fn test_permission_checking() {
1440        let owner = UserInfo {
1441            name: "Dr. Test".to_string(),
1442            email: "test@example.com".to_string(),
1443            institution: "Test University".to_string(),
1444            avatar_url: None,
1445            timezone: "UTC".to_string(),
1446            language: "en".to_string(),
1447            research_interests: vec![],
1448        };
1449
1450        let workspace = CollaborativeWorkspace::new("Test Workspace", owner);
1451        let owner_id = &workspace.members[0].id;
1452
1453        assert!(workspace.has_permission(owner_id, &Permission::Read));
1454        assert!(workspace.has_permission(owner_id, &Permission::Write));
1455        assert!(workspace.has_permission(owner_id, &Permission::ManageMembers));
1456
1457        // Test non-existent user
1458        assert!(!workspace.has_permission("non-existent", &Permission::Read));
1459    }
1460}